GetCurrentProcessID、OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges

GetCurrentProcessID、OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges

2007-08-24 17:34
GetCurrentProcessID            得到当前进程的ID   
OpenProcessToken          得到进程的令牌句柄
LookupPrivilegeValue          查询进程的权限
AdjustTokenPrivileges          判断令牌权限  

            要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以 了。要是一个用户是Administrator或是被给予了相应的权限,就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安 全进程执行OpenProcess(PROCESS_ALL_ACCESS,FALSE,          dwProcessID)还是会遇到“访问拒绝”的错误。什么原因呢?原来在默认的情况下进程的一些访问权限是没有被使能(Enabled)的,所以我们 要做的首先是使能这些权限。与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、 AdjustTokenPrivileges。我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过 OpenProcessToken得到,函数的原型如下:

BOOL      OpenProcessToken(
            HANDLE      ProcessHandle,        //要修改访问权限的进程句柄
            DWORD      DesiredAccess,        //指定你要进行的操作类型
            PHANDLE      TokenHandle         //返回的访问令牌指针
     );

            第一参数是要修改访问权限的进程句柄;第三个参数就是返回的访问令牌指针;第二个参数指定你要进行的操作类型,如要修改令牌我们要指定第二个参数为 TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform          SDK)。通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。接着我们可 以调用AdjustTokenPrivileges对这个访问令牌进行修改。AdjustTokenPrivileges的原型如下:

BOOL AdjustTokenPrivileges(
       HANDLE TokenHandle,                        // 访问令牌的句柄
       BOOL DisableAllPrivileges,                   // 决定是进行权限修改还是除能(Disable)所有权限
       PTOKEN_PRIVILEGES NewState,         // 指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构
                                                                     的指针,该结构包含一个数组,数据组的每个项指明了权限
                                                                     的类型和要进行的操作;
       DWORD BufferLength,                         //结构PreviousState的长度,如果PreviousState为空,该参数
                                                                       应为NULL
       PTOKEN_PRIVILEGES PreviousState,   // 指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问
                                                                      权限的信息
       PDWORD ReturnLength                       //实际PreviousState结构返回的大小
);

            第一个参数是访问令牌的句柄;第二个参数决定是进行权限修改还是除能(Disable)所有权限;第三个参数指明要修改的权限,是一个指向 TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数据组的每个项指明了权限的类型和要进行的操作;          第四个参数是结构PreviousState的长度,如果PreviousState为空,该参数应为NULL;第五个参数也是一个指向 TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息,可空;最后一个参数为实际PreviousState结构返回的大小。在使用 这个函数前再看一下TOKEN_PRIVILEGES这个结构,其声明如下:

typedef          struct          _TOKEN_PRIVILEGES          {   
          DWORD          PrivilegeCount;   
          LUID_AND_ATTRIBUTES          Privileges[];   
}TOKEN_PRIVILEGES,          *PTOKEN_PRIVILEGES;   

            PrivilegeCount指的数组原素的个数,接着是一个LUID_AND_ATTRIBUTES类型的数组,再来看一下LUID_AND_ATTRIBUTES这个结构的内容,声明如下:

typedef          struct          _LUID_AND_ATTRIBUTES          {   
            LUID              Luid;   
            DWORD            Attributes;   
}LUID_AND_ATTRIBUTES,          *PLUID_AND_ATTRIBUTES

            第二个参数就指明了我们要进行的操作类型,有三个可选项:  
   
SE_PRIVILEGE_ENABLED
SE_PRIVILEGE_ENABLED_BY_DEFAULT
SE_PRIVILEGE_USED_FOR_ACCESS

要使能一个权限就指定Attributes为SE_PRIVILEGE_ENABLED。第一个参数就是指权限的类型,是一个LUID的值,LUID就是 指locally          unique          identifier,我想GUID大家是比较熟悉的,和GUID的要求保证全局唯一不同,LUID只要保证局部唯一,就是指在系统的每一次运行期间保证 是唯一的就可以了。另外和GUID相同的一点,LUID也是一个64位的值,相信大家都看过GUID那一大串的值,我们要怎么样才能知道一个权限对应的 LUID值是多少呢?这就要用到另外一个API函数LookupPrivilegevalue,其原形如下:

BOOL LookupPrivilegeValue(
       LPCTSTR lpSystemName,     //系统的名称,若为空,则在当前的sysytem查找。
       LPCTSTR lpName,                 // 指明了权限的名称,如“SeDebugPrivilege”。
       PLUID lpLuid                          // 返回LUID的指针
);

            第一个参数是系统的名称,如果是本地系统只要指明为NULL就可以了,第三个参数就是返回LUID的指针,第二个参数就是指明了权限的名称,如“SeDebugPrivilege”。在Winnt.h中还定义了一些权限名称的宏,如:

#define          SE_BACKUP_NAME                        TEXT("SeBackupPrivilege")
#define          SE_RESTORE_NAME                     TEXT("SeRestorePrivilege")
#define          SE_SHUTDOWN_NAME                  TEXT("SeShutdownPrivilege")
#define          SE_DEBUG_NAME                          TEXT("SeDebugPrivilege")

这样通过这三个函数的调用,我们就可以用OpenProcess(PROCESS_ALL_ACCESS,FALSE,          dwProcessID)来打获得任意进程的句柄,并且指定了所有的访问权。
MSDN例程:

Displaying the Shutdown Dialog Box

 

The following example uses the InitiateSystemShutdown function to begin the system shutdown process on the computer on which is user is logged on. The application must first enable the SE_SHUTDOWN_NAME privilege. For more information, see Privileges.

 

BOOL MySystemShutdown( LPTSTR lpMsg )
{
   HANDLE hToken;              // handle to process token 
   TOKEN_PRIVILEGES tkp;       // pointer to token structure 
 
   BOOL fResult;               // system shutdown flag 
 
   // Get the current process token handle so we can get shutdown 
   // privilege. 
 
   if (!OpenProcessToken(GetCurrentProcess(), 
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
      return FALSE; 
 
   // Get the LUID for shutdown privilege. 
 
   LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, 
        &tkp.Privileges[0].Luid); 
 
   tkp.PrivilegeCount = 1;  // one privilege to set    
   tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
 
   // Get shutdown privilege for this process. 
 
   AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
      (PTOKEN_PRIVILEGES) NULL, 0); 
 
   // Cannot test the return value of AdjustTokenPrivileges. 
 
   if (GetLastError() != ERROR_SUCCESS) 
      return FALSE; 
 
   // Display the shutdown dialog box and start the countdown. 
 
   fResult = InitiateSystemShutdown( 
      NULL,    // shut down local computer 
      lpMsg,   // message for user
      20,      // time-out period 
      FALSE,   // ask user to close apps 
      TRUE);   // reboot after shutdown 
 
   if (!fResult) 
      return FALSE; 
 
   // Disable shutdown privilege. 
 
   tkp.Privileges[0].Attributes = 0; 
   AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
        (PTOKEN_PRIVILEGES) NULL, 0); 
 
   return TRUE; 
}

If the AbortSystemShutdown function is executed in the time-out period specified by InitiateSystemShutdown, the system does not shut down.

BOOL PreventSystemShutdown()
{
   HANDLE hToken;              // handle to process token 
   TOKEN_PRIVILEGES tkp;       // pointer to token structure 
 
   // Get the current process token handle  so we can get shutdown 
   // privilege. 
 
   if (!OpenProcessToken(GetCurrentProcess(), 
         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
      return FALSE; 
 
   // Get the LUID for shutdown privilege. 
 
   LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, 
         &tkp.Privileges[0].Luid); 
 
   tkp.PrivilegeCount = 1;  // one privilege to set    
   tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
 
   // Get shutdown privilege for this process. 
 
   AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
        (PTOKEN_PRIVILEGES)NULL, 0); 
 
   if (GetLastError() != ERROR_SUCCESS) 
      return FALSE; 
 
   // Prevent the system from shutting down. 
 
   if ( !AbortSystemShutdown(NULL) ) 
      return FALSE; 
 
   // Disable shutdown privilege. 
 
   tkp.Privileges[0].Attributes = 0; 
   AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, 
       (PTOKEN_PRIVILEGES) NULL, 0); 
 
   return TRUE;
}

 

#include <windows.h> #include <tlhelp32.h> #include <stdio.h> #include <psapi.h> #include <sddl.h> // 全局变量 DWORD_PTR g_HookAddr = 0; // Hook 目标地址 DWORD_PTR g_OriginalFunc = 0; // 原始函数地址 PVOID g_VehHandler = nullptr; // VEH 句柄 bool g_Is64BitProcess = false; // 进程位数标识 // 调试寄存器控制值 #ifdef _WIN64 const DWORD DR7_EXECUTE_ENABLED = (1 << 0) | (0 << 16) | (0 << 18); // L0=1, R/W0=00 (执行) #else const DWORD DR7_EXECUTE_ENABLED = 0x00000401; // L0=1, R/W0=00 (执行) #endif // 函数声明 LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo); bool EnableDebugPrivilege(); bool SetHardwareBreakpoint(HANDLE hThread, DWORD_PTR address); void SetCurrentThreadBreakpoint(); void SetAllThreadsBreakpoints(); void LogToFile(const char* format, ...); void InitializeHook(); void MonitorNewThreads(); // VEH 异常处理函数 LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) { if ((DWORD_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress == g_HookAddr) { // ====== Hook 逻辑 ====== const char* text = nullptr; const char* caption = nullptr; #ifdef _WIN64 // 64位系统:参数在寄存器中 text = (const char*)ExceptionInfo->ContextRecord->Rcx; caption = (const char*)ExceptionInfo->ContextRecord->R8; #else // 32位系统:参数在栈上 DWORD* stack = (DWORD*)ExceptionInfo->ContextRecord->Esp; text = (const char*)stack[1]; caption = (const char*)stack[2]; #endif // 记录调用信息 LogToFile("[VEH HOOK] MessageBoxA called\n"); LogToFile(" Text: %s\n", text ? text : "NULL"); LogToFile(" Caption: %s\n", caption ? caption : "NULL"); LogToFile(" Thread ID: %d\n\n", GetCurrentThreadId()); // ====== 恢复执行 ====== // 清除单步标志防止无限循环 ExceptionInfo->ContextRecord->EFlags &= ~0x100; // 继续执行原始函数 #ifdef _WIN64 ExceptionInfo->ContextRecord->Rip = g_OriginalFunc; #else ExceptionInfo->ContextRecord->Eip = g_OriginalFunc; #endif return EXCEPTION_CONTINUE_EXECUTION; } } return EXCEPTION_CONTINUE_SEARCH; } // 启用调试权限 bool EnableDebugPrivilege() { HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { return false; } TOKEN_PRIVILEGES tp; LUID luid; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { CloseHandle(hToken); return false; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { CloseHandle(hToken); return false; } CloseHandle(hToken); return GetLastError() == ERROR_SUCCESS; } // 设置硬件断点 bool SetHardwareBreakpoint(HANDLE hThread, DWORD_PTR address) { CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; if (!GetThreadContext(hThread, &ctx)) { return false; } // 选择可用的调试寄存器 if (ctx.Dr0 == 0) { ctx.Dr0 = address; } else if (ctx.Dr1 == 0) { ctx.Dr1 = address; } else if (ctx.Dr2 == 0) { ctx.Dr2 = address; } else if (ctx.Dr3 == 0) { ctx.Dr3 = address; } else { // 所有调试寄存器已使用 return false; } ctx.Dr7 |= DR7_EXECUTE_ENABLED; return SetThreadContext(hThread, &ctx); } // 设置当前线程的硬件断点 void SetCurrentThreadBreakpoint() { HANDLE hThread = GetCurrentThread(); SetHardwareBreakpoint(hThread, g_HookAddr); } // 遍历并设置所有线程的硬件断点 void SetAllThreadsBreakpoints() { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return; THREADENTRY32 te32; te32.dwSize = sizeof(THREADENTRY32); DWORD currentProcessId = GetCurrentProcessId(); DWORD currentThreadId = GetCurrentThreadId(); if (Thread32First(hSnapshot, &te32)) { do { if (te32.th32OwnerProcessID == currentProcessId && te32.th32ThreadID != currentThreadId) { // 尝试打开线程 HANDLE hThread = OpenThread( THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID ); if (!hThread) { DWORD err = GetLastError(); LogToFile("Failed to open thread %d: %d\n", te32.th32ThreadID, err); continue; } // 暂停线程 DWORD suspendCount = SuspendThread(hThread); if (suspendCount != (DWORD)-1) { // 设置硬件断点 if (!SetHardwareBreakpoint(hThread, g_HookAddr)) { LogToFile("Failed to set breakpoint for thread %d\n", te32.th32ThreadID); } ResumeThread(hThread); } CloseHandle(hThread); } } while (Thread32Next(hSnapshot, &te32)); } CloseHandle(hSnapshot); } // 监控新线程创建 void MonitorNewThreads() { // 使用事件钩子监控线程创建 // 实际应用中应使用更可靠的方法(如PsSetCreateThreadNotifyRoutine) LogToFile("Thread monitoring started\n"); } // 安全的日志记录函数 void LogToFile(const char* format, ...) { FILE* logFile = nullptr; if (fopen_s(&logFile, "veh_hook_log.txt", "a") == 0 && logFile) { va_list args; va_start(args, format); vfprintf(logFile, format, args); va_end(args); fclose(logFile); } } // 初始化 Hook void InitializeHook() { // 1. 启用调试权限 EnableDebugPrivilege(); // 2. 获取目标函数地址 HMODULE hUser32 = LoadLibraryA("user32.dll"); if (!hUser32) { LogToFile("Failed to load user32.dll\n"); return; } g_HookAddr = (DWORD_PTR)GetProcAddress(hUser32, "MessageBoxA"); if (!g_HookAddr) { LogToFile("Failed to get MessageBoxA address\n"); return; } g_OriginalFunc = g_HookAddr; LogToFile("Hook target: 0x%p\n", (void*)g_HookAddr); // 3. 注册 VEH 异常处理 g_VehHandler = AddVectoredExceptionHandler(1, VectoredExceptionHandler); if (!g_VehHandler) { LogToFile("Failed to register VEH handler\n"); return; } LogToFile("VEH handler registered: 0x%p\n", g_VehHandler); // 4. 设置所有现有线程的硬件断点 SetAllThreadsBreakpoints(); // 5. 设置当前线程的硬件断点 SetCurrentThreadBreakpoint(); // 6. 启动线程监控 MonitorNewThreads(); LogToFile("VEH Hook initialized successfully\n"); } // DLL 入口点 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hModule); // 创建新线程初始化 Hook HANDLE hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)InitializeHook, nullptr, 0, nullptr); if (hThread) CloseHandle(hThread); break; case DLL_PROCESS_DETACH: if (g_VehHandler) { RemoveVectoredExceptionHandler(g_VehHandler); LogToFile("VEH handler unregistered\n"); } break; } return TRUE; } 严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误 C2360 “hThread”的初始化操作由“case”标签跳过 veh hook C:\Users\17116\source\repos\veh hook\veh hook\源.cpp 258
最新发布
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值