首页
社区
课程
招聘
[原创]拦截Windows关机消息
发表于: 2022-12-4 00:17 18913

[原创]拦截Windows关机消息

2022-12-4 00:17
18913

写了一个小工具,可以通过Hook Winlogon进程主模块的导入表、延迟导入表来拦截对于User32!ExitWindowsEx函数的调用

整个步骤如下:

1、启动一个进程,注入DLL到Winlogon进程

  (1) 因为winlogon进程是system级别进程,所以要让注入进程已管理员方式启动,并使能SeDebugPrivilege权限,这样才可以注入system进程。

  (2) 通过进程枚举获取到winlogon进程的PID,这个过程还可以判断session会话,因为同一时刻,系统中可能存在多个winlogon进程。

  (3) 打开此进程,可以使用PROCESS_ALL_ACCESS标志。

  (4) 在目标进程winlogon进程中申请内存,并写入需要注入的DLL对应的路径名称,写入绝对路径名称。

  (5) 通过远线程注入,启动函数为LoadLibraryA(W),传入参数为目标进程中需要注入DLL的路径地址。

2、在DLL的入口函数DllMain中HOOk 导入表,延迟导入表

  (1) 通过尝试,在windows 7 x86中,winlogon进程是在导入表中引用了User32模块的ExitWindowsEx函数。

  (2) 而在 Windows 10 1809 x64中,winlogon进程是在延迟导入表中引用了User32模块的ExitWindowsEx函数。所以直接对这两个表都进行修复即可

3、Hook函数指向自己写的函数,在自己写的函数中编写功能代码

  (1) 通过尝试,Winlogon进程会调用两次ExitWindowsEx函数,调用时使用的标志数据uFlags是不一样的,第一次调用ExitWindowsEx时会向桌面进程发送一些用户注销或者关机消息,用户进程可以在此时处理以便需要保存的内容。所有进程都处理完成后,第一次调用的ExitWindowsEx函数就返回TRUE了,否则返回FALSE。

  (2) 如果第一次调用ExitWindowsEx成功,那么就说明桌面进程都同意关机或者注销了,会第二次调用ExitWindowsEx函数,需要意识到第二次调用前,桌面进程都被销毁了,此时如果要显示一个程序窗口,我们需要在桌面"WinSta0\winlogon"上进行显示,指定STARTUPINFOA(W)的lpDesktop指向此字符串。

  备注:在windows 7上存在会话隔离,服务进程默认处于会话0(Session 0)下,所以窗口正常情况下都看不见,Windows启动后的第一个Winlogon进程为会话1,Winlogon下创建了工作站WinSta0,在此工作站下创建了桌面"WinSta0\winlogon",登录对话框就是显示在这个桌面上的,当用户成功登录后,显示的桌面为"WinSta0\Default",也就是说一般情况下我们看到的的程序都运行在WinSta0\Default桌面上,Winlogon进程还创建了桌面"WinSta0\Disconnect"。可以通过Process Explorer工具来查看某个进程中的句柄,可以看到类似的桌面都打开了WindowsStation对象,对应的名称为\Sessions\1\Windows\WindowStations\WinSta0 不同的会话对应的会话ID不同,所以WindowsStation对象对应的Name为\Sessions\XXX\Windows\WindowStations\WinSta0。SysinternalsSuite套件中提供了一个工具叫做Desktops.exe,这个工具除了当前默认的桌面外,还可以模拟出3个桌面,查看此进程可以看到共对应四个Desktop对象,分别为:【\Default】、【\Sysinternals Desktop 1】、【\Sysinternals Desktop 2】、【\Sysinternals Desktop 3】,通过Alt 1、2、3、4即可在四个桌面之间快速进行切换。

  通过上面的知识,我们可以选择在Winlogon进程第二次调用ExitWindowsEx前,进行拦截,可以弹窗提示告知用户即将关机,或者显示其它消息。因为第一次ExitWindowsEx返回TRUE才会进行第二次调用,表明用户进程都已知晓,如果有未保存文件,此时用户都已知晓并处理过了。

  当第一次调用ExitWindowsEx成功后,此时Windows桌面已经进入到了上面所说的WinSta0\winlogon下,所以调用CreateProcessAsUserA(W)时需要指定对应的桌面。

4、需要考虑到我们的DLL是运行在system进程中的,而提示时需要启动一个新的进程,最好不要让这个进程拥有过高权限,所以我们使用CreateProcessAsUserA(W)来创建进程。

  通过尝试,在第二次调用ExitWindowsEx前,我们先打开当前进程,因为之后需要复制token,再修改token进程等级。但是在打开当前进程时程序执行失败,所以我们选择在DllMain函数中创建好一个Token进行保存,在调用CreateProcessAsUserA(W)使用这个token就可以了。

注入进程代码如下:

被注入的DLL代码如下:

其中引用了warningUser.h文件内容如下:

源文件warningUser.cpp文件内容为:

在提示进程LogOffWillRun中,代码很简单,进行提示,如下

代码基本到此结束,运行注入DLL的进程时需要以管理员权限运行。

winlogon调用两次ExitWindowsEx后,wininit进程会去调用ntdll!NtShutDownSystem进程进行关机。在win 10 1809 x64上,发现wininit会进行第三次调用ExitWindowsEx函数。本来想远线程注入wininit进程,但是失败,错误代码为8,含义为内存资源不足,无法处理此命令。

还有一个想法是Hook wininit进程,具体如下:

1、打开wininit进程

2、远程修改导入表,Hook NtShutDownSystem

  (1) 可以通过在本进程中调用LoadLibraryExA(W)展开wininit的PE文件,定位到NtShutDownSystem函数对应的地址,通过此地址与内存中的wininit映像计算一个偏移。

  (2)枚举wininit进程模块,获取主进程基地址,然后通过上一步的偏移量来修改导入表或者延迟导入表。

  (3)修改地址为一段shellcode的起始地址,并保留原来wininit中导入表的内容

    a、远程申请一段空间,可读可写可执行,这段空间包括两部分内容,第一部分是数据,第二部分是代码。

    b、数据是原来导入表的内容,也可以写入其它数据。

    c、代码可以使用PIC_Bindshell项目,然后自己编写C语言函数,编写一段shellcode,引用之前的数据(可以通过call pop重定位或者生成shellcode后,通过每次修改shellcode硬编码来引用数据)。

3、修改导入表后,Hook函数指针指向我们自己的shellcode(如果数据与代码在连续内存,记得加上偏移,使指针指向shellcode起始地址),当wininit调用NtShutDownSystem时会先调用我们自己的函数,使用PIC_Bindshell编写代码可以加载我们自己的动态库,调用动态库导出函数来启动一个进程提示用户关机了。

备注:winlogon进程调用两次ExitWindowsEx后程序就退出了,如果我们选择注销当前用户,当前winlogon结束,会启动新的winlogon,此时没有我们注入的动态库,即可以将注入器写成服务进程,后台枚举winlogon进程,注入DLL。或者HOOk Wininit进程。也可以在桌面进程中监听窗口消息WM_QUERYENDSESSION。或者在服务进程中通过RegisterServiceCtrlHandlerA(W)注册一个回调函数,在回调函数中处理SERVICE_CONTROL_SHUTDOWN请求。

2022-12-28添加:在Hook的ExitWindowsEx函数中也可以通过MessageBox来提示用户,如下:

效果如下:
图片描述
如果是通过启动一个新进程的方式,优点是更加灵活,自己编写新进程,不需要修改DLL。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#include <Windows.h>
#include <iostream>
#include <Psapi.h>
#include <Tlhelp32.h>
#include <sddl.h>
#include <Shlwapi.h>
 
using namespace std;
#pragma comment (lib,"advapi32.lib")
#pragma comment (lib,"Shlwapi.lib")
 
VOID InjectToWinLogon()
{   
    PROCESSENTRY32 entry;
    HANDLE snapshot = NULL, proc = NULL;
    entry.dwSize = sizeof(PROCESSENTRY32);
    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
 
    INT pid = -1;
    if (Process32First(snapshot, &entry))
    {
        while (Process32Next(snapshot, &entry))
        {
            if (wcscmp(entry.szExeFile, L"winlogon.exe") == 0)
            {               
                pid = entry.th32ProcessID;
                break;
            }
        }
    }
    CloseHandle(snapshot);
    if (pid < 0)
    {
        //puts("[-] Could not find winlogon.exe");
        return;
    }  
    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (proc == NULL)
    {
        DWORD error = GetLastError();
        puts("[-] Failed to open process.");
        printf("error %d\n", error);
        return;
    }
    TCHAR buffDll[MAX_PATH] = { 0 };
    GetModuleFileName(NULL, buffDll, _countof(buffDll));
    PathRemoveFileSpec(buffDll);
    _tcscat_s(buffDll, _countof(buffDll), L"\\DllHookExitWindowsEx.dll");   
    LPVOID buffer = VirtualAllocEx(proc, NULL, sizeof(buffDll), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (buffer == NULL)
    {
        printf("[-] Failed to allocate remote memory");
    }
    if (!WriteProcessMemory(proc, buffer, buffDll, sizeof(buffDll), 0))
    {
        puts("[-] Failed to write to remote memory");
        return;
    }       
    LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW");
    HANDLE hthread = CreateRemoteThread(proc, 0, 0, (LPTHREAD_START_ROUTINE)start, buffer, 0, 0);   
 
    DWORD error = GetLastError();
    if (hthread == INVALID_HANDLE_VALUE)
    {
        puts("[-] Failed to create remote thread");
        return;
    }
}
 
void EnableSeDebugPrivilegePrivilege()
{
    LUID luid;
    HANDLE currentProc = OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId());
    if (currentProc)
    {
        HANDLE TokenHandle = NULL;
        BOOL hProcessToken = OpenProcessToken(currentProc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle);
        if (hProcessToken)
        {
            BOOL checkToken = LookupPrivilegeValue(NULL, L"SeDebugPrivilege", &luid);
 
            if (!checkToken)
            {
                //std::cout << "[+] Current process token already includes SeDebugPrivilege\n" << std::endl;
            }
            else
            {
                TOKEN_PRIVILEGES tokenPrivs;
 
                tokenPrivs.PrivilegeCount = 1;
                tokenPrivs.Privileges[0].Luid = luid;
                tokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
                BOOL adjustToken = AdjustTokenPrivileges(TokenHandle, FALSE, &tokenPrivs, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL);
 
                if (adjustToken != 0)
                {
                    //std::cout << "[+] Added SeDebugPrivilege to the current process token" << std::endl;
                }
            }
            CloseHandle(TokenHandle);
        }
    }
    CloseHandle(currentProc);
}
 
int _tmain(int argc, _TCHAR* argv[])
{                
    //开启权限 使之可以注入到syetem进程
    EnableSeDebugPrivilegePrivilege();
    //注入dll
    InjectToWinLogon();
 
    getchar();
    return 0;
}
#include <Windows.h>
#include <iostream>
#include <Psapi.h>
#include <Tlhelp32.h>
#include <sddl.h>
#include <Shlwapi.h>
 
using namespace std;
#pragma comment (lib,"advapi32.lib")
#pragma comment (lib,"Shlwapi.lib")
 
VOID InjectToWinLogon()
{   
    PROCESSENTRY32 entry;
    HANDLE snapshot = NULL, proc = NULL;
    entry.dwSize = sizeof(PROCESSENTRY32);
    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
 
    INT pid = -1;
    if (Process32First(snapshot, &entry))
    {
        while (Process32Next(snapshot, &entry))
        {
            if (wcscmp(entry.szExeFile, L"winlogon.exe") == 0)
            {               
                pid = entry.th32ProcessID;
                break;
            }
        }
    }
    CloseHandle(snapshot);
    if (pid < 0)
    {
        //puts("[-] Could not find winlogon.exe");
        return;
    }  
    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (proc == NULL)
    {
        DWORD error = GetLastError();
        puts("[-] Failed to open process.");
        printf("error %d\n", error);
        return;
    }
    TCHAR buffDll[MAX_PATH] = { 0 };
    GetModuleFileName(NULL, buffDll, _countof(buffDll));
    PathRemoveFileSpec(buffDll);
    _tcscat_s(buffDll, _countof(buffDll), L"\\DllHookExitWindowsEx.dll");   
    LPVOID buffer = VirtualAllocEx(proc, NULL, sizeof(buffDll), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (buffer == NULL)
    {
        printf("[-] Failed to allocate remote memory");
    }
    if (!WriteProcessMemory(proc, buffer, buffDll, sizeof(buffDll), 0))
    {
        puts("[-] Failed to write to remote memory");
        return;
    }       
    LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW");
    HANDLE hthread = CreateRemoteThread(proc, 0, 0, (LPTHREAD_START_ROUTINE)start, buffer, 0, 0);   
 
    DWORD error = GetLastError();
    if (hthread == INVALID_HANDLE_VALUE)
    {
        puts("[-] Failed to create remote thread");
        return;
    }
}
 
void EnableSeDebugPrivilegePrivilege()
{
    LUID luid;
    HANDLE currentProc = OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId());
    if (currentProc)
    {
        HANDLE TokenHandle = NULL;
        BOOL hProcessToken = OpenProcessToken(currentProc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle);
        if (hProcessToken)
        {
            BOOL checkToken = LookupPrivilegeValue(NULL, L"SeDebugPrivilege", &luid);
 
            if (!checkToken)
            {
                //std::cout << "[+] Current process token already includes SeDebugPrivilege\n" << std::endl;
            }
            else
            {
                TOKEN_PRIVILEGES tokenPrivs;
 
                tokenPrivs.PrivilegeCount = 1;
                tokenPrivs.Privileges[0].Luid = luid;
                tokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
                BOOL adjustToken = AdjustTokenPrivileges(TokenHandle, FALSE, &tokenPrivs, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL);
 
                if (adjustToken != 0)
                {
                    //std::cout << "[+] Added SeDebugPrivilege to the current process token" << std::endl;
                }
            }
            CloseHandle(TokenHandle);
        }
    }
    CloseHandle(currentProc);
}
 
int _tmain(int argc, _TCHAR* argv[])
{                
    //开启权限 使之可以注入到syetem进程
    EnableSeDebugPrivilegePrivilege();
    //注入dll
    InjectToWinLogon();
 
    getchar();
    return 0;
}
#include <Windows.h>
#include <Psapi.h>
#include <Tlhelp32.h>
 
#include "warningUser.h"
 
#include <Shlwapi.h>
#include <stdlib.h>
#include <tchar.h>
 
#pragma comment (lib,"Shlwapi.lib")
 
LPVOID _copyNtShutdownSystem = NULL;
LPVOID _ExitWindowsExAddTwoByte = NULL;
HMODULE _gloDllModule = NULL;
 
 
#pragma warning(disable:4996)
 
/*__declspec(naked)*/ void MyExitWindowsEx()
{
    /*__asm
    {
        call testMsgBox;
        jmp _ExitWindowsExAddTwoByte
    }*/
}
 
typedef BOOL(WINAPI* FuncExitWindowsEx)(_In_ UINT uFlags, _In_ DWORD dwReason);
FuncExitWindowsEx _OldExitWindowsEx = NULL;
 
 
HANDLE gloCreateProcessHandle = NULL;
 
BOOL WINAPI IATHookExitWindowsEx(_In_ UINT uFlags, _In_ DWORD dwReason)
{   
    BOOL bRet = FALSE;
    static BOOL bNeedWarning = FALSE;
    //__asm int 3
    //DebugBreak();
 
    /*if (uFlags & 0x200000)//win7 x86可以通过这句来判断是否是第二次调用 通过调试获得的   需要测试
    {       
    }*/
    if (bNeedWarning)
    {
        TCHAR wszProcessName[MAX_PATH] = { 0 };
        GetModuleFileName(_gloDllModule, wszProcessName, _countof(wszProcessName));
        PathRemoveFileSpec(wszProcessName);
        _tcscat_s(wszProcessName, _countof(wszProcessName), L"\\LogOffWillRun.exe");
        useTokenCreateProcess(gloCreateProcessHandle, wszProcessName);
    }
 
    bRet = _OldExitWindowsEx(uFlags, dwReason);
    if (bRet)
    {       
        bNeedWarning = TRUE;       
    }   
    return bRet;   
}
 
//这是 win7 x86上的 Iniline Hook
void hook_ExitWindowsEx()
{   
    HMODULE hUser32 = GetModuleHandle(L"user32.dll");
    char* pOldExitWindowsEx = (char*)GetProcAddress(hUser32, "ExitWindowsEx");
    char* pOldAddr = pOldExitWindowsEx;   
 
    //00540000 8bff            mov     edi, edi   
    int iLengthCopy = 7;
    if (NULL != pOldAddr)
    {
        _copyNtShutdownSystem = VirtualAlloc(0, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        char* pNewAddr = (char*)_copyNtShutdownSystem;
 
        char* pnop = pOldAddr - 5; //5个字节的NOP
        char aa = *pOldAddr;
        char bb = *(pOldAddr+1);
        if ((char)0x8b == *pOldAddr && (char)0xff == *(pOldAddr+1))
        {
            DWORD oldshutdownProtect = 0;
            if (VirtualProtect(pOldAddr-5, iLengthCopy, PAGE_EXECUTE_READWRITE, &oldshutdownProtect))
            {
                //*pOldNtShutdownSyetem = (char)0xe9;//jmp
                *pOldExitWindowsEx = (char)0xeB;//jmp 短跳转
                *(UCHAR*)(pOldExitWindowsEx + 1) = (USHORT)(-0x7); //addr
 
                *pnop = (char)0xe9;//jmp
                *(int*)(pnop + 1) = (int)MyExitWindowsEx-(int)(pnop + 5); //addr
                _ExitWindowsExAddTwoByte = pOldExitWindowsEx + 2;
                VirtualProtect(pOldAddr-5, iLengthCopy, oldshutdownProtect, NULL);
            }
        }       
    }
    return;
}
 
BYTE* getNtHdrs(BYTE* pe_buffer)
{
    if (pe_buffer == NULL) return NULL;
 
    IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)pe_buffer;
    if (idh->e_magic != IMAGE_DOS_SIGNATURE) {
        return NULL;
    }
    const LONG kMaxOffset = 1024;
    LONG pe_offset = idh->e_lfanew;
    if (pe_offset > kMaxOffset) return NULL;
    IMAGE_NT_HEADERS32* inh = (IMAGE_NT_HEADERS32*)((BYTE*)pe_buffer + pe_offset);
    if (inh->Signature != IMAGE_NT_SIGNATURE) return NULL;
    return (BYTE*)inh;
}
 
IMAGE_DATA_DIRECTORY* getPeDir(PVOID pe_buffer, size_t dir_id)
{
    if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL;
 
    BYTE* nt_headers = getNtHdrs((BYTE*)pe_buffer);
    if (nt_headers == NULL) return NULL;
 
    IMAGE_DATA_DIRECTORY* peDir = NULL;
 
    IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)nt_headers;
    peDir = &(nt_header->OptionalHeader.DataDirectory[dir_id]);
 
    if (peDir->VirtualAddress == NULL) {
        return NULL;
    }
    return peDir;
 
}
 
bool FixDelayIATHook(PVOID modulePtr)
{   
    IMAGE_DATA_DIRECTORY* importsDir = getPeDir(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
    if (importsDir == NULL) return false;
 
    size_t maxSize = importsDir->Size;
    size_t impAddr = importsDir->VirtualAddress;
 
    IMAGE_DELAYLOAD_DESCRIPTOR* lib_desc = NULL;
    size_t parsedSize = 0;
    bool bFound = TRUE;
 
    size_t addrExitWindowsEx = (size_t)GetProcAddress(GetModuleHandle(L"User32"), "ExitWindowsEx");   
 
    for (; parsedSize < maxSize; parsedSize += sizeof(IMAGE_DELAYLOAD_DESCRIPTOR)) {
 
        lib_desc = (IMAGE_DELAYLOAD_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr);
 
        if (lib_desc->ImportAddressTableRVA == NULL && lib_desc->ImportNameTableRVA == NULL) break;
 
        LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->DllNameRVA);       
 
        size_t call_via = lib_desc->ImportAddressTableRVA;
        size_t thunk_addr = lib_desc->ImportNameTableRVA;
        if (thunk_addr == NULL) thunk_addr = lib_desc->ImportAddressTableRVA;
 
        size_t offsetField = 0;
        size_t offsetThunk = 0;       
        for (;; offsetField += sizeof(IMAGE_THUNK_DATA), offsetThunk += sizeof(IMAGE_THUNK_DATA))
        {
            IMAGE_THUNK_DATA* fieldThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetField + call_via);
            IMAGE_THUNK_DATA* orginThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetThunk + thunk_addr);
 
            if (0 == fieldThunk->u1.Function && 0 == orginThunk->u1.Function)
            {
                break;
            }           
            PIMAGE_IMPORT_BY_NAME by_name = NULL;
            LPSTR func_name = NULL;
            size_t addrOld = NULL;
            if (orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32 || orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) // check if using ordinal (both x86 && x64)
            {
                addrOld = (size_t)GetProcAddress(LoadLibraryA(lib_name), (char*)(orginThunk->u1.Ordinal & 0xFFFF));//通过序号也可以获取到  获取低两个字节 也可以获取到函数地址
                //printf("        [V] API %x at %x\n", orginThunk->u1.Ordinal, addr);
                //fieldThunk->u1.Function = addr;               
                continue;
            }
            else
            {
                by_name = (PIMAGE_IMPORT_BY_NAME)(size_t(modulePtr) + orginThunk->u1.AddressOfData);
                func_name = (LPSTR)by_name->Name;
                addrOld = (size_t)GetProcAddress(LoadLibraryA(lib_name), func_name);
            }                       
            //printf("        [V] API %s at %x\n", func_name, addr);
            OutputDebugStringA("\r\n");
            OutputDebugStringA(func_name);
            //HOOK           
            if (strcmpi(func_name, "ExitWindowsEx") == 0)
            {               
                //DebugBreak();
                DWORD dOldProtect = 0;
                size_t* pFuncAddr = (size_t*)&fieldThunk->u1.Function;
                if (VirtualProtect(pFuncAddr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dOldProtect))
                {
                    fieldThunk->u1.Function = (size_t)IATHookExitWindowsEx;
                    VirtualProtect(pFuncAddr, sizeof(size_t), dOldProtect, &dOldProtect);
                    _OldExitWindowsEx = (FuncExitWindowsEx)addrExitWindowsEx;
                    bFound = true;
                    return bFound;
                }               
                break;
            }
 
        }
 
    }   
    return true;
}
 
bool FixIATHook(PVOID modulePtr)
{
    IMAGE_DATA_DIRECTORY* importsDir = getPeDir(modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
    if (importsDir == NULL) return false;
 
    size_t maxSize = importsDir->Size;
    size_t impAddr = importsDir->VirtualAddress;
 
    IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL;
    size_t parsedSize = 0;
    bool bFound = TRUE;   
    size_t addrExitWindowsEx = (size_t)GetProcAddress(GetModuleHandle(L"User32"), "ExitWindowsEx");
 
    for (; parsedSize < maxSize; parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
        lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr);
        if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL)
            break;
 
        LPSTR lib_name = (LPSTR)((size_t)modulePtr + lib_desc->Name);
 
        size_t call_via = lib_desc->FirstThunk;
        size_t thunk_addr = lib_desc->OriginalFirstThunk;
        if (thunk_addr == NULL)
            thunk_addr = lib_desc->FirstThunk;
 
        size_t offsetField = 0;
        size_t offsetThunk = 0;
 
        for (;; offsetField += sizeof(IMAGE_THUNK_DATA), offsetThunk += sizeof(IMAGE_THUNK_DATA))
        {
            IMAGE_THUNK_DATA* fieldThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetField + call_via);
            IMAGE_THUNK_DATA* orginThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetThunk + thunk_addr);
 
            if (0 == fieldThunk->u1.Function && 0 == orginThunk->u1.Function)
            {
                break;
            }
 
            PIMAGE_IMPORT_BY_NAME by_name = NULL;
            LPSTR func_name = NULL;
            size_t addrOld = NULL;
            if (orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32 || orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) // check if using ordinal (both x86 && x64)
            {
                addrOld = (size_t)GetProcAddress(LoadLibraryA(lib_name), (char*)(orginThunk->u1.Ordinal & 0xFFFF));//通过序号?
                //printf("        [V] API %x at %x\n", orginThunk->u1.Ordinal, addr);
                //fieldThunk->u1.Function = addr;   
                //DebugBreak();
                continue;
            }
            else
            {
                by_name = (PIMAGE_IMPORT_BY_NAME)(size_t(modulePtr) + orginThunk->u1.AddressOfData);
                func_name = (LPSTR)by_name->Name;
                addrOld = (size_t)GetProcAddress(LoadLibraryA(lib_name), func_name);
            }
            //printf("        [V] API %s at %x\n", func_name, addr);
            OutputDebugStringA("\r\n");
            OutputDebugStringA(func_name);
            //HOOK           
            if (strcmpi(func_name, "ExitWindowsEx") == 0)
            {               
                //DebugBreak();                                               
                DWORD dOldProtect = 0;
                size_t* pFuncAddr = (size_t*)&fieldThunk->u1.Function;
                if (VirtualProtect(pFuncAddr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dOldProtect))
                {
                    fieldThunk->u1.Function = (size_t)IATHookExitWindowsEx;
                    VirtualProtect(pFuncAddr, sizeof(size_t), dOldProtect, &dOldProtect);
                    _OldExitWindowsEx = (FuncExitWindowsEx)addrExitWindowsEx;
                    bFound = true;
                    return bFound;
                }               
            }
        }               
    }
    return true;   
}
 
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
 
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {       
        //DebugBreak();
        _gloDllModule = hModule;
        gloCreateProcessHandle = getMediumProcessToken();      
        HMODULE exeModule = GetModuleHandle(NULL);       
        FixIATHook(exeModule);
        FixDelayIATHook(exeModule);               
        break;
    }       
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    {
        if (gloCreateProcessHandle != NULL)
        {
            CloseHandle(gloCreateProcessHandle);
            gloCreateProcessHandle = NULL;
        }
    }
        break;
    }
    return TRUE;
}
#include <Windows.h>
#include <Psapi.h>
#include <Tlhelp32.h>
 
#include "warningUser.h"
 
#include <Shlwapi.h>
#include <stdlib.h>
#include <tchar.h>
 
#pragma comment (lib,"Shlwapi.lib")
 
LPVOID _copyNtShutdownSystem = NULL;
LPVOID _ExitWindowsExAddTwoByte = NULL;
HMODULE _gloDllModule = NULL;
 
 
#pragma warning(disable:4996)
 
/*__declspec(naked)*/ void MyExitWindowsEx()
{
    /*__asm
    {
        call testMsgBox;
        jmp _ExitWindowsExAddTwoByte
    }*/
}
 
typedef BOOL(WINAPI* FuncExitWindowsEx)(_In_ UINT uFlags, _In_ DWORD dwReason);
FuncExitWindowsEx _OldExitWindowsEx = NULL;
 
 
HANDLE gloCreateProcessHandle = NULL;
 
BOOL WINAPI IATHookExitWindowsEx(_In_ UINT uFlags, _In_ DWORD dwReason)
{   
    BOOL bRet = FALSE;
    static BOOL bNeedWarning = FALSE;
    //__asm int 3
    //DebugBreak();
 
    /*if (uFlags & 0x200000)//win7 x86可以通过这句来判断是否是第二次调用 通过调试获得的   需要测试
    {       
    }*/
    if (bNeedWarning)
    {
        TCHAR wszProcessName[MAX_PATH] = { 0 };
        GetModuleFileName(_gloDllModule, wszProcessName, _countof(wszProcessName));
        PathRemoveFileSpec(wszProcessName);
        _tcscat_s(wszProcessName, _countof(wszProcessName), L"\\LogOffWillRun.exe");
        useTokenCreateProcess(gloCreateProcessHandle, wszProcessName);
    }
 
    bRet = _OldExitWindowsEx(uFlags, dwReason);
    if (bRet)
    {       
        bNeedWarning = TRUE;       
    }   
    return bRet;   
}
 
//这是 win7 x86上的 Iniline Hook
void hook_ExitWindowsEx()
{   
    HMODULE hUser32 = GetModuleHandle(L"user32.dll");
    char* pOldExitWindowsEx = (char*)GetProcAddress(hUser32, "ExitWindowsEx");
    char* pOldAddr = pOldExitWindowsEx;   
 
    //00540000 8bff            mov     edi, edi   
    int iLengthCopy = 7;
    if (NULL != pOldAddr)
    {
        _copyNtShutdownSystem = VirtualAlloc(0, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        char* pNewAddr = (char*)_copyNtShutdownSystem;
 
        char* pnop = pOldAddr - 5; //5个字节的NOP
        char aa = *pOldAddr;
        char bb = *(pOldAddr+1);
        if ((char)0x8b == *pOldAddr && (char)0xff == *(pOldAddr+1))
        {
            DWORD oldshutdownProtect = 0;
            if (VirtualProtect(pOldAddr-5, iLengthCopy, PAGE_EXECUTE_READWRITE, &oldshutdownProtect))
            {
                //*pOldNtShutdownSyetem = (char)0xe9;//jmp
                *pOldExitWindowsEx = (char)0xeB;//jmp 短跳转
                *(UCHAR*)(pOldExitWindowsEx + 1) = (USHORT)(-0x7); //addr
 
                *pnop = (char)0xe9;//jmp
                *(int*)(pnop + 1) = (int)MyExitWindowsEx-(int)(pnop + 5); //addr
                _ExitWindowsExAddTwoByte = pOldExitWindowsEx + 2;
                VirtualProtect(pOldAddr-5, iLengthCopy, oldshutdownProtect, NULL);
            }
        }       
    }
    return;
}
 
BYTE* getNtHdrs(BYTE* pe_buffer)
{
    if (pe_buffer == NULL) return NULL;
 
    IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)pe_buffer;
    if (idh->e_magic != IMAGE_DOS_SIGNATURE) {
        return NULL;
    }
    const LONG kMaxOffset = 1024;
    LONG pe_offset = idh->e_lfanew;
    if (pe_offset > kMaxOffset) return NULL;
    IMAGE_NT_HEADERS32* inh = (IMAGE_NT_HEADERS32*)((BYTE*)pe_buffer + pe_offset);
    if (inh->Signature != IMAGE_NT_SIGNATURE) return NULL;
    return (BYTE*)inh;
}
 
IMAGE_DATA_DIRECTORY* getPeDir(PVOID pe_buffer, size_t dir_id)
{
    if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL;
 
    BYTE* nt_headers = getNtHdrs((BYTE*)pe_buffer);
    if (nt_headers == NULL) return NULL;
 
    IMAGE_DATA_DIRECTORY* peDir = NULL;
 
    IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)nt_headers;
    peDir = &(nt_header->OptionalHeader.DataDirectory[dir_id]);
 
    if (peDir->VirtualAddress == NULL) {
        return NULL;
    }
    return peDir;
 
}
 
bool FixDelayIATHook(PVOID modulePtr)
{   
    IMAGE_DATA_DIRECTORY* importsDir = getPeDir(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
    if (importsDir == NULL) return false;
 
    size_t maxSize = importsDir->Size;
    size_t impAddr = importsDir->VirtualAddress;
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-12-28 13:47 被0346954编辑 ,原因:
收藏
免费 7
支持
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  mb_ubaeeisi   +1.00 2023/11/13 有个同样的的开发需求,有兴趣吗,稍作修改即可,QQ:707075614 微信:18628302518(手机同号)
最新回复 (7)
雪    币: 2081
活跃值: (1716)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主,能拦截所有的文件访问消息吗 ?
2022-12-4 09:27
0
雪    币: 3710
活跃值: (5861)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
3
拦截文件访问这种需要驱动来做吧,文件系统过滤监控。
2022-12-4 10:16
0
雪    币: 2081
活跃值: (1716)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
0346954 拦截文件访问这种需要驱动来做吧,文件系统过滤监控。

能提供或推荐一些资料吗? 我想实现自己的文件过滤。只在本机使用

最后于 2022-12-4 12:09 被goldli编辑 ,原因: 修改
2022-12-4 12:01
0
雪    币: 3710
活跃值: (5861)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
5
有Windows驱动开发的书,看 《Windows内核编程》 谭文 陈铭霖著
2022-12-4 14:04
0
雪    币: 2081
活跃值: (1716)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
0346954 有Windows驱动开发的书,看 《Windows内核编程》 谭文 陈铭霖著
谢谢
2022-12-4 17:59
0
雪    币: 22
活跃值: (438)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
MARK
2022-12-4 20:48
0
雪    币: 300
活跃值: (2387)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark
2022-12-5 11:40
0
游客
登录 | 注册 方可回帖
返回
//