Tot*_*ion 1 c assembly kernel ida
我试图读取某些进程的内存,如csrss.exe使用OpenProcess().问题是,一旦我使用PROCESS_ALL_ACCESS这些进程就无法打开.所以我尝试使用PROCESS_QUERY_LIMITED_INFORMATION参数,但不会获得多汁的结果.
根据我对系统的理解,这个功能最终会调用ZwOpenProcess().我目前的理解是,如果应用程序在用户模式下访问它,则此调用也将被视为来自用户模式而不是内核模式的调用.
为了绕过这个检查,我做了以下事情:
ntdll.dll所有这些进程所在的位置.
所以再次从我的理解,它执行测试,然后如果它评估为0,它执行低延迟系统调用,我相信这是函数的内核模式版本.
接下来我做了同样的事情ZwReadVirtualMemory():

所以这是我的问题:
PROCESS_ALL_ACCESS如果我使用上述方法调用它们,将适用于这些例程.VirtualQueryEx()我找不到内核模式替换,在这种情况下,我打算VirtualQueryEx()与上面提到的自定义调用一起使用.现在我的问题是,因为VirtualQueryEx()不是内核模式调用(至少在顶部,我的意思是ReadProcessMemory()调用ZwReadVirtualMemory但是如果由用户模式程序启动则不是内核模式调用,情况也是如此VirtualQueryEx()),这是一个问题,还是在我进行下一次自定义调用时会恢复到用户模式?我自己做这一切的最终目标是能够使用内核级特权打开所有进程,读取内存并将其转储到文件中.这还包括在系统级运行的进程,如csrss.exe.如果存在任何更简单的方法,请用同样的方式启发我.
Code :
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HANDLE lProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
DWORD error = GetLastError();
if (hProc || lProc)
{
//(!hProc && lProc) ? printf("lproc") : printf("hProc"); //Testing Condition
fProc = (!hProc && lProc) ? lProc : hProc;
while (1) {
if ((VirtualQueryEx(fProc, addr1, &meminfo, sizeof(meminfo))) == 0)
{
break;
}
if ((meminfo.State == MEM_COMMIT))
{
static unsigned char display_buffer[1024 * 128];
SIZE_T bytes_left;
SIZE_T total_read;
SIZE_T bytes_to_read;
SIZE_T bytes_read;
FILE *f;
f = fopen("Dump.txt", "a");
addr = (unsigned char*)meminfo.BaseAddress;
//printf("Process Name : %ws\r\n", pName.Buffer);
fprintf(f, "Process Name : %ws\r\n", pName.Buffer);
//printf("Base Address : 0x%08x\r\n", addr);
fprintf(f, "Base Address : 0x%08x\r\n", addr);
bytes_left = meminfo.RegionSize;
//printf("Region Size : %d\r\n", bytes_left);
fprintf(f, "Region Size : %d\r\n", bytes_left);
total_read = 0;
//printf("Contents : \r\n");
fprintf(f, "Contents : \r\n");
while (bytes_left)
{
bytes_to_read = (bytes_left > sizeof(display_buffer)) ? sizeof(display_buffer) : bytes_left;
ReadProcessMemory(hProc, addr + total_read, display_buffer, bytes_to_read, &bytes_read);
if (bytes_read != bytes_to_read) break;
int j = 0;
for (j = 0; j < bytes_to_read; j++)
{
if ((display_buffer[j] > 31) && (display_buffer[j] < 127)) {
//printf("%c ", display_buffer[j]);
fprintf(f, "%c", display_buffer[j]);
}
else {
//printf(".");
fprintf(f, ".");
}
}
//printf("\r\n");
fprintf(f, "\r\n");
bytes_left -= bytes_read;
total_read += bytes_read;
}
fclose(f);
}
addr1 = (unsigned char*)meminfo.BaseAddress + meminfo.RegionSize;
}
}
else {
printf("\nFailed to open process - error - %d\r\n", error);
}
Run Code Online (Sandbox Code Playgroud)
所以,这里我试图将所有内存信息保存到给定进程的DUMP.txt文件中.
感谢RbMm指出,自Windows 10以来,情况发生了变化.实际上,他们从Windows Vista开始改变.
Windows Vista引入了受保护进程的概念,以强制将DRM应用于媒体内容.
正常过程(除了其他限制之外)无法读取或修改受保护的进程.
受保护的进程只能在签名时加载,并且只有在它们仅执行一组受限操作时才能加载.
在Windows 8.1中,Microsoft重新访问了受保护的进程,并引入了Protected Process Light(PPL)类进程.
PPL只能由另一个PPL启动; 使用安全启动或使用特定的注册表项/环境变量,关键系统进程是PPL.
这意味着即使通过管理员/系统帐户也无法打开它们.
csrss.exe 也是Windows 8.1以来的PPL:
请注意,有趣的是Csrss.exe也具有保护级别.它不负责启动任何特殊的受保护进程,并且在内存中没有任何有趣的数据,如LSASS或系统进程.然而,近年来它作为多个Windows漏洞的来源获得了非常邪恶的声誉
除了保护级别外,每个进程还有一个签名者.
此字段指定进程在系统中的运行方式.价值观是:
PsProtectedSignerNone = 0n0
PsProtectedSignerAuthenticode = 0n1
PsProtectedSignerCodeGen = 0n2
PsProtectedSignerAntimalware = 0n3
PsProtectedSignerLsa = 0n4
PsProtectedSignerWindows = 0n5
PsProtectedSignerWinTcb = 0n6
PsProtectedSignerMax/PsProtectedSignerWinSystem = 0n7
Run Code Online (Sandbox Code Playgroud)
最后,每个签名者类型都有一个结构确定:
每个签名者但PsProtectedSignerNone限制了特权
PROCESS_QUERY_LIMITED_INFORMATION
PROCESS_SUSPEND_RESUME
PROCESS_TERMINATE (excluding WinTcb, Antimalware and Lsa)
PROCESS_SET_LIMITED_INFORMATION
Run Code Online (Sandbox Code Playgroud)
为了打开csrss.exe必要的运行请求过程作为受保护的进程与适当的签名者,但这需要二进制文件由Microsoft 签名.或者,正如RbMm指出的那样,如果您可以加载内核驱动程序,则可以使用该EPROCESS结构进行调整,从而改变保护级别位.
这个非常简单的程序打开了一个由SYSTEM启动的过程.
#include <windows.h>
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
HANDLE thisProcess = GetCurrentProcess();
HANDLE thisToken;
TOKEN_PRIVILEGES newPrivileges;
HANDLE thatProcess;
newPrivileges.PrivilegeCount = 1;
newPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (LookupPrivilegeValue(NULL, "SeDebugPrivilege", &newPrivileges.Privileges[0].Luid) == 0)
{
MessageBox(NULL, "LookupPrivilegeValue", "Cannot find privilege", MB_ICONEXCLAMATION);
ExitProcess(1);
}
if (OpenProcessToken(thisProcess, TOKEN_ADJUST_PRIVILEGES, &thisToken) == 0)
{
MessageBox(NULL, "OpenProcessToken", "Cannot open token", MB_ICONEXCLAMATION);
ExitProcess(2);
}
AdjustTokenPrivileges(thisToken, FALSE, &newPrivileges, 0, NULL, NULL);
if (GetLastError() != ERROR_SUCCESS)
{
MessageBox(NULL, "AdjustTokenPrivileges", "Cannot adjust privileges", MB_ICONEXCLAMATION);
ExitProcess(3);
}
thatProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1080);
if (thatProcess == NULL)
{
MessageBox(NULL, "OpenProcess", "Cannot open that process", MB_ICONEXCLAMATION);
ExitProcess(4);
}
MessageBox(NULL, "Done", "Opened", MB_ICONINFORMATION);
}
Run Code Online (Sandbox Code Playgroud)
在具有SeDebugPrivilege的帐户(例如管理员帐户)下运行时,它会成功获取进程句柄.
当不在上述条件下运行时,它在该AdjustTokenPrivileges步骤失败.
我在我的系统上进行了测试,将其作为一个成熟的管理员和普通用户运行.只有管理员可以打开它.
它的工作原理正如我在之前的评论中所解释的那样:它在其访问令牌中启用SeDebugPrivilege,然后打开任意系统进程句柄.
注意进程ID是硬编码的,请更改它.
要理解的一件重要事情是AdjustTokenPrivileges 无法添加新权限,它只能启用/禁用进程从用户继承的权限.
据我所知,没有公共API可以为访问令牌添加新权限.
如果程序在非管理用户下运行,则该过程将失败,因为没有理智的管理员会向任何非管理员授予如此强大的权限.
此外,即使您的帐户是管理员帐户,您也可能作为受保护的管理员运行,因此分配给流程的令牌将不具备SeDebugPrivilege.
您可以通过以完全管理员身份运行或通过自我提升流程来解决此问题.
我目前的理解是,如果应用程序在用户模式下访问它,则此调用也将被视为来自用户模式而不是内核模式的调用.
这种理解是不正确的.
从用户空间无法访问的内核,有一个入口点将控制权从用户空间转移到内核,但用户程序无法读取/写入内核内存.
有关系统的每个重要信息(包括句柄)都保存在内核中,远离用户程序的范围.
当程序使用系统调用转换到内核时,它也放弃对内核的控制; 简单地说,你可以执行一个设计的内核函数,但你不能读/写它的代码或数据.
这是一个架构(读取CPU)约束,即使经常发现漏洞绕过它,它也非常强大.
如果您正在寻找这样的漏洞,那么您正在寻找零日漏洞.
操作系统中的错误.
显然,访问权限检查由内核代码执行,因此除非您将程序作为内核的一部分,否则您无法查看,触摸或绕过它.
这是一个驱动程序,您可以使用WDK(而不是SDK)开发一个驱动程序.
加载驱动程序仍然需要管理权限,但管理员或特权设置可以使驱动程序在启动时加载(它们是一种服务,它们不需要用户).
实际上,在这种情况下,服务应该足够了.
您在反汇编中看到的检查只是一个兼容性路径,Windows使用该syscall指令而不是旧版本int 2eh.
我以为遗留机制已经消失了.
两个路径最终将在内核中合并.
所以再次从我的理解,它执行测试,然后如果它评估为0,它执行低延迟系统调用,我相信这是函数的内核模式版本
如上所述,这是不正确的.
您可以感觉到它不可能是真的,因为两个路径中都没有代码(函数的非内核模式版本在哪里?).
我可以直接创建.asm文件并在其中编写这些过程并调用它们以获取内核模式访问这些函数吗?
代码直接调用系统调用,此接口是私有的.
Microsoft保留自行更改系统调用号码和/或调用约定的权利.
只有公共API在不同版本的Windows上才是稳定的.
如果需要,可以通过执行以下操作直接调用系统调用:
mov r10, rcx
mov eax, 26h
syscall
Run Code Online (Sandbox Code Playgroud)
然后按照您的方式在寄存器中设置参数NtOpenProcess.
你不会得到任何地方,这只是原始功能的内联,非便携版本.
如果我使用上述方法调用它们,PROCESS_ALL_ACCESS是否适用于这些例程.
不,检查仍然由内核执行.
我还需要使用我无法找到内核模式替换的VirtualQueryEx(),在这种情况下,我计划使用VirtualQueryEx()以及上面提到的自定义调用.现在我的问题是,因为VirtualQueryEx()不是内核模式调用(至少在顶部,我的意思是ReadProcessMemory()也调用ZwReadVirtualMemory但是如果由用户模式程序启动则不是内核模式调用,所以是VirtualQueryEx()的情况,它是一个问题还是当我进行下一次自定义调用时它会恢复到用户模式?
我无法完全理解这个问题,对此我很抱歉.
我只能说:a)WinAPI和私有API是两组不同的API b)WinAPI不以1:1的方式使用私有API,它们可能涉及多个系统调用(Fun fact) :似乎Windows使用系统调用,即使代码已经在环0)c)所有特权操作都由内核执行,这不是调用程序的选择.
我自己做这一切的最终目标是能够使用内核级特权打开所有进程,读取内存并将其转储到文件中.这还包括在系统级运行的进程,如csrss.exe.如果存在任何更简单的方法,请用同样的方式启发我.
内核没有权限,用户拥有权限,因此拥有进程.
您应该能够使用作为管理员运行的程序或作为System运行的服务来转储任何用户模式进程.