如果注入器由特定应用程序启动,PE 注入会失败吗?
PE injection fails if injector gets launched by specific application?
简短免责声明:由于此问题包含有关 hacking/pentesting 的主题,我想声明此问题仅作为学校项目的一部分用于教育目的。为了防止可能的滥用,我将只 post 理解问题所必需的代码。
为了演示 Windows10 的危险和漏洞,我目前正在编写一个小型 C++/WinAPI 应用程序,它使用两种常用技术:
- 使用“fodhelper technique”绕过 UAC(这只需将特定的注册表值设置为应该提升的可执行文件的路径,然后启动自动提升的 Windows名为“
fodhelper.exe
”的可执行文件随后将读取注册表值并将其作为 command/launch 指定应用程序执行)。
- 执行PE注入,即运行从当前进程的地址space(基于this example from github)注入一个PE文件。在我的程序中注入的 PE 是一个简单的 C++ 控制台应用程序 (x86),它会打印一个消息框。 shellcode 硬编码在注入器二进制文件 (x86) 中。
我设法在独立文件中成功地执行了这两种技术。但是,一旦我将这两种方法结合起来(即先提升,然后注入),就会出现一个奇怪的错误。
问题描述
当注入器手动启动(通过双击)时,一切正常,但是当注入器由于 UAC 绕过而由 System32\fodhelper.exe
(x64) 启动时,会发生以下情况:注入已完成,注入应用程序的控制台 window 出现,但我没有继续执行,而是收到一堆错误消息,指出“The code execution cannot proceed because [garbage characters].dll was not found
”。这表明偏移量出了点问题,Windows 加载程序正试图在错误的位置读取导入。
总结:代码注入工作正常,除非注入器由 fodhelper.exe
启动。在这种情况下,注入的 PE 文件无法 运行.
到目前为止,我已尝试找出问题的根源
- 使用
GetLastError
调试注入并打印注入期间使用的各种内存地址。手动启动文件(注入成功)和fodhelper.exe
启动文件(注入失败)没有区别。
- 将
WriteProcessMemory
调用替换为 WriteFile
以比较手动启动注入器或 fodhelper.exe
时的输出文件。两个输出文件完全相同并且 运行nable。这表明注入本身不是问题,但 Windows 加载程序似乎表现不同。
- 使用 UAC 或使用提升的命令提示符手动提升注入器。两种情况都注入成功。
- 正在将
fodhelper.exe
复制到另一个位置(例如到桌面)并启动此副本。在这种情况下,注入成功。仅当注入器由 System32
文件夹中的原始 fodhelper.exe
启动时注入才会失败。
似乎注入行为完全相同,但指标显示由于 fodhelper.exe 传递给注入器的一些未知影响,Windows 加载程序似乎表现不同。
感谢任何解释或假设!如果您需要更多信息,请随时询问。
最小可重现示例
(调试信息和注释有限):
https://0bin.net/paste/UPRIg12n#6nJvBok72UcDvIa56c-XEss7AibIh1Zrs+c3sUzvQMj
注意:如果排除 elevateProcess
函数或使用 UAC 手动提升 exe,请查看注入如何工作,以及包含所述函数时注入如何失败。
编辑
根据用户 RbMm 的回答,此错误是自动应用于 fodhelper.exe
和似乎被所有子进程继承。据此,启动目标进程时的removing/resetting这个属性应该修复错误。到目前为止,我已经尝试了以下方法,但结果没有任何改变:
DWORD resetPolicy = 0;
STARTUPINFOEXA siEx = { 0 };
SIZE_T AttributeListSize = 0;
siEx.StartupInfo.cb = sizeof(siEx);
InitializeProcThreadAttributeList(NULL, 1, 0, &AttributeListSize);
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, AttributeListSize);
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &AttributeListSize);
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &resetPolicy, sizeof(resetPolicy), NULL, NULL);
...
CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&siEx, &PI);
当进程通过 RunAs 创建并提升时 - appinfo.dll 调用 RAiLaunchAdminProcess函数(这是在一些svchost.exe)和这个函数,将STARTUPINFOEX
(和EXTENDED_STARTUPINFO_PRESENT
标志)传递给CreateProcessAsUser
。这里 - lpAttributeList,特别是 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
attribute key is used for set several exploit mitigation policy for the child process (fodhelper.exe in your case). and here EnableModuleTamperingProtection
is set for child process tree. effect of this - when system resolve import descriptor, it check (inside LdrpGetImportDescriptorForSnap) for this mitigation flag, and if it enabled - call LdrpCheckPagesForTampering
api, it return true, if SharedOriginal
是 0,这意味着这是 EXE/IAT 的写时复制私有副本——因此 'tampered' 与。
在调用 LdrpMapCleanModuleView 之后。此时你的尝试开始失败
可能第一个 public 关于这个的信息,来自 Alex Ionescu -
LdrpCheckPagesForTampering/LdrpMapCleanModuleView (RS3) are pretty
cool antihollowing mitigations
(EPROCESS.EnableModuleTamperingProtection)
如果您自行启动新进程,您当然不会为设置 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
调用 UpdateProcThreadAttribute
,在这种情况下,您的代码 有时 可以工作。真的只是随机的,有时 - 这里存在许多其他错误和糟糕的编码
简短免责声明:由于此问题包含有关 hacking/pentesting 的主题,我想声明此问题仅作为学校项目的一部分用于教育目的。为了防止可能的滥用,我将只 post 理解问题所必需的代码。
为了演示 Windows10 的危险和漏洞,我目前正在编写一个小型 C++/WinAPI 应用程序,它使用两种常用技术:
- 使用“fodhelper technique”绕过 UAC(这只需将特定的注册表值设置为应该提升的可执行文件的路径,然后启动自动提升的 Windows名为“
fodhelper.exe
”的可执行文件随后将读取注册表值并将其作为 command/launch 指定应用程序执行)。 - 执行PE注入,即运行从当前进程的地址space(基于this example from github)注入一个PE文件。在我的程序中注入的 PE 是一个简单的 C++ 控制台应用程序 (x86),它会打印一个消息框。 shellcode 硬编码在注入器二进制文件 (x86) 中。
我设法在独立文件中成功地执行了这两种技术。但是,一旦我将这两种方法结合起来(即先提升,然后注入),就会出现一个奇怪的错误。
问题描述
当注入器手动启动(通过双击)时,一切正常,但是当注入器由于 UAC 绕过而由 System32\fodhelper.exe
(x64) 启动时,会发生以下情况:注入已完成,注入应用程序的控制台 window 出现,但我没有继续执行,而是收到一堆错误消息,指出“The code execution cannot proceed because [garbage characters].dll was not found
”。这表明偏移量出了点问题,Windows 加载程序正试图在错误的位置读取导入。
总结:代码注入工作正常,除非注入器由 fodhelper.exe
启动。在这种情况下,注入的 PE 文件无法 运行.
到目前为止,我已尝试找出问题的根源
- 使用
GetLastError
调试注入并打印注入期间使用的各种内存地址。手动启动文件(注入成功)和fodhelper.exe
启动文件(注入失败)没有区别。 - 将
WriteProcessMemory
调用替换为WriteFile
以比较手动启动注入器或fodhelper.exe
时的输出文件。两个输出文件完全相同并且 运行nable。这表明注入本身不是问题,但 Windows 加载程序似乎表现不同。 - 使用 UAC 或使用提升的命令提示符手动提升注入器。两种情况都注入成功。
- 正在将
fodhelper.exe
复制到另一个位置(例如到桌面)并启动此副本。在这种情况下,注入成功。仅当注入器由System32
文件夹中的原始fodhelper.exe
启动时注入才会失败。
似乎注入行为完全相同,但指标显示由于 fodhelper.exe 传递给注入器的一些未知影响,Windows 加载程序似乎表现不同。
感谢任何解释或假设!如果您需要更多信息,请随时询问。
最小可重现示例
(调试信息和注释有限): https://0bin.net/paste/UPRIg12n#6nJvBok72UcDvIa56c-XEss7AibIh1Zrs+c3sUzvQMj
注意:如果排除 elevateProcess
函数或使用 UAC 手动提升 exe,请查看注入如何工作,以及包含所述函数时注入如何失败。
编辑
根据用户 RbMm 的回答,此错误是自动应用于 fodhelper.exe
和似乎被所有子进程继承。据此,启动目标进程时的removing/resetting这个属性应该修复错误。到目前为止,我已经尝试了以下方法,但结果没有任何改变:
DWORD resetPolicy = 0;
STARTUPINFOEXA siEx = { 0 };
SIZE_T AttributeListSize = 0;
siEx.StartupInfo.cb = sizeof(siEx);
InitializeProcThreadAttributeList(NULL, 1, 0, &AttributeListSize);
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, AttributeListSize);
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &AttributeListSize);
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &resetPolicy, sizeof(resetPolicy), NULL, NULL);
...
CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&siEx, &PI);
当进程通过 RunAs 创建并提升时 - appinfo.dll 调用 RAiLaunchAdminProcess函数(这是在一些svchost.exe)和这个函数,将STARTUPINFOEX
(和EXTENDED_STARTUPINFO_PRESENT
标志)传递给CreateProcessAsUser
。这里 - lpAttributeList,特别是 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
attribute key is used for set several exploit mitigation policy for the child process (fodhelper.exe in your case). and here EnableModuleTamperingProtection
is set for child process tree. effect of this - when system resolve import descriptor, it check (inside LdrpGetImportDescriptorForSnap) for this mitigation flag, and if it enabled - call LdrpCheckPagesForTampering
api, it return true, if SharedOriginal
是 0,这意味着这是 EXE/IAT 的写时复制私有副本——因此 'tampered' 与。
在调用 LdrpMapCleanModuleView 之后。此时你的尝试开始失败
可能第一个 public 关于这个的信息,来自 Alex Ionescu -
LdrpCheckPagesForTampering/LdrpMapCleanModuleView (RS3) are pretty cool antihollowing mitigations (EPROCESS.EnableModuleTamperingProtection)
如果您自行启动新进程,您当然不会为设置 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
调用 UpdateProcThreadAttribute
,在这种情况下,您的代码 有时 可以工作。真的只是随机的,有时 - 这里存在许多其他错误和糟糕的编码