<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    使用Windows API繞過進程保護

    VSole2021-11-18 07:19:54

    前言

    最近在研究某數字殺軟的時候看到有個配置選項:

    img

    這個自我保護實際上是加載360SelfProtection.sys驅動(看這名字應該還有360SelfProtection_win10.sys文件),在0環通過hook等手段保護注冊表項,重要進程進程等。

    img

    比如這里要結束某核心進程,會顯示無法結束,拒絕訪問。

    img

    img

    這個并不是說權限不夠的問題,即便是system權限也不行。而是由于在底層,殺死進程的API已經被hook了,這里應該是內核hook,當想要結束的進程為核心進程時,就直接返回一個無法終止進程的彈窗。本文就如何實現一個進程保護功能進行探究,驅動就不寫了,就寫一個用戶層的。

    實現原理

    windows提供了一個可以殺死其他進程的API:TerminateProcess。如果是結束本身進程為:ExitProcess。

    BOOL TerminateProcess(
    [in] HANDLE hProcess,
    [in] UINT   uExitCode
    );
    

    通過命令taskkill或者通過任務管理器等GUI工具去結束進程,本質上都是調用的TerminateProcess,有些可能是調用更為底層的ZwTerminateProcess,但是本質都差不多,只是看該進程用的什么API,這里為了方便就使用TerminateProcess進行演示。

    通過hook TerminateProcess讓執行該函數時直接返回沒有權限。

    獲取API地址并創建新的hook函數

    static BOOL(WINAPI* OldTerminateProcess)(
        HANDLE hProcess,
        UINT   uExitCode) = TerminateProcess;
    BOOL WINAPI New_TerminateProcess(
    _In_ HANDLE hProcess,
    _In_ UINT uExitCode
    ) {
        unhookTerminateProcess();
    MessageBox(NULL,L"該進程受保護!", L"Access Denied",NULL);
        hookTerminateProcess();
    returnfalse;
    }
    

    這里是64位的進程,要改變的硬編碼是12個字節,而且不需要去算偏移。

    48 b8 _dwNewAddress(0x1122334455667788)
    ff e0
    mov rax, _dwNewAddress(0x1122334455667788)
    jmp rax
    

    將原來函數的調轉地址改為我們自己函數的跳轉地址

    void hookTerminateProcess() {
        DWORD dwTerminateProcessOldProtect;
        BYTE pData[12] = { 0x48,0xb8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xE0};
        ULONGLONG ullNewFuncAddr = (ULONGLONG)New_TerminateProcess;
    //保存本來的字節
    ::RtlCopyMemory(g_OldTerminateProcess, OldTerminateProcess, sizeof(pData));
    //更改權限
    VirtualProtect(OldTerminateProcess, 12, PAGE_EXECUTE_READWRITE, &dwTerminateProcessOldProtect);
    //更改原來的機器碼,改為我們自己函數的地址
    ::RtlCopyMemory(&pData[2], &ullNewFuncAddr, sizeof(ullNewFuncAddr));
    ::RtlCopyMemory(OldTerminateProcess, pData, sizeof(pData));
    //恢復屬性
    VirtualProtect(OldTerminateProcess, 12, dwTerminateProcessOldProtect, &dwTerminateProcessOldProtect);
    }
    

    恢復硬編碼,還原調轉地址。

    void unhookTerminateProcess() {
        DWORD dwOldProtect = NULL;
    //改為可寫屬性
    VirtualProtect(OldTerminateProcess, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    //還原原來的硬編碼
    RtlCopyMemory(OldTerminateProcess, g_OldTerminateProcess, sizeof(g_OldTerminateProcess));
    //還原屬性
    VirtualProtect(OldTerminateProcess, 12, dwOldProtect, &dwOldProtect);
    }
    

    最方便的就是寫成一個dll,這樣注入到任務管理器并起一個線程跑就行了。

    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
    )
    {
    switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
            hookTerminateProcess();
    break;
    case DLL_THREAD_ATTACH:
    break;
    case DLL_THREAD_DETACH:
    break;
    case DLL_PROCESS_DETACH:
            unhookTerminateProcess();
    break;
    }
    return TRUE;
    }
    

    注入這里也是為了練手,稍微寫了一個注入程序,為了以后的方法寫成了突破session 0的注入。

    #include
    #include
    #include"tchar.h"
    #include
    usingnamespace std;
    BOOL EnbalePrivileges(HANDLE hProcess, LPCWSTR pszPrivilegesName)
    {
        HANDLE hToken = NULL;
        LUID luidValue = { 0};
        TOKEN_PRIVILEGES tokenPrivileges = { 0};
        BOOL bRet = FALSE;
        DWORD dwRet = 0;
    // 打開進程令牌并獲取進程令牌句柄
        bRet = ::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
    if(FALSE == bRet)
    {
            printf("[!] Open CurrentProcessToken Error,Error is:%d",GetLastError());
    return FALSE;
    }
    else
    {
            printf("[*] Open CurrentProcessToken Successfully!,TokenHandle is:%d", hToken);
    }
    // 獲取本地系統的 pszPrivilegesName 特權的LUID值
        bRet = ::LookupPrivilegeValue(NULL, pszPrivilegesName, &luidValue);
    if(FALSE == bRet)
    {
            printf("[!] LookupPrivilegeValue Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
            printf("[*] LookupPrivilegeValue Successfully!");
    }
    // 設置提升權限信息
        tokenPrivileges.PrivilegeCount= 1;
        tokenPrivileges.Privileges[0].Luid= luidValue;
        tokenPrivileges.Privileges[0].Attributes= SE_PRIVILEGE_ENABLED;
    // 提升進程令牌訪問權限
        bRet = ::AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, 0, NULL, NULL);
    if(FALSE == bRet)
    {
            printf("[!] AdjustTokenPrivileges Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    // 根據錯誤碼判斷是否特權都設置成功
            dwRet = ::GetLastError();
    if(ERROR_SUCCESS == dwRet)
    {
                printf("[√] ALL_ASSIGNED!");
    return TRUE;
    }
    elseif(ERROR_NOT_ALL_ASSIGNED == dwRet)
    {
                printf("[!] ERROR:NOT_ALL_ASSIGNED,Error is %d", dwRet);
    return FALSE;
    }
    }
    return FALSE;
    }
    DWORD EnumModules(DWORD hPid, LPCSTR hMoudlePath)
    {
        WCHAR szBuffer[MAX_PATH] = { 0};
        mbstowcs(szBuffer, hMoudlePath, MAX_PATH);
    //通過pid列出所有的Modules
        HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
        MODULEENTRY32    me32;
    //給進程所引用的模塊信息設定一個快照
        hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, hPid);
    if(hModuleSnap == INVALID_HANDLE_VALUE)
    {
            printf("[!] Error:Enum modules failed to detect if there is an injected DLL module,error is %d",GetLastError());
    }
        me32.dwSize = sizeof(MODULEENTRY32);
    if(!Module32First(hModuleSnap, &me32))
    {
            printf("[!] Enum Error!");
    CloseHandle(hModuleSnap);
    }
    do
    {
    if(!memcmp(me32.szExePath, szBuffer,MAX_PATH))
    return1;           
    } while(Module32Next(hModuleSnap, &me32));
    CloseHandle(hModuleSnap);
    return0;
    }
    DWORD _InjectThread(DWORD _Pid, LPCSTR psDllPath)
    {
        FILE* fp;
        fp = fopen(psDllPath, "r");
    if(!fp)
    {
            printf("[!] Error:DLL path not foundPlease check that your path is correct or absolute");
    return FALSE;
    }
        fclose(fp);
        printf("****************************************************************************");
        HANDLE hprocess = NULL;
        HANDLE hThread = NULL;
        DWORD _SIZE = 0;
        LPVOID pAlloc = NULL;
        FARPROC pThreadFunction = NULL;
        DWORD ZwRet= 0;
        hprocess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, _Pid);
    if(hprocess == NULL)
    {
    printf("[!] OpenProcess Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] OpenProcess Successfully!");
    }
    _SIZE = strlen(psDllPath)+1;
    pAlloc = ::VirtualAllocEx(hprocess, NULL, _SIZE, MEM_COMMIT, PAGE_READWRITE);
    if(pAlloc == NULL)
    {
    printf("[!] VirtualAllocEx Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] VirtualAllocEx Successfully!");
    }
    BOOL x = ::WriteProcessMemory(hprocess, pAlloc, psDllPath, _SIZE, NULL);
    if(FALSE == x)
    {
    printf("[!] WriteMemory Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] WriteMemory Successfully!");
    }
    HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
    if(hNtdll == NULL)
    {
    printf("[!] LoadNTdll Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] Load ntdll.dll Successfully!");
    }
    pThreadFunction = ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
    if(pThreadFunction == NULL)
    {
    printf("[!] Get LoadLibraryA Address Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] Get LoadLibraryA Address Successfully! Address is %x", pThreadFunction);
    }
    #ifdef _WIN64
    typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    LPVOID ObjectAttributes,
    HANDLE ProcessHandle,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    ULONG CreateThreadFlags,
    SIZE_T ZeroBits,
    SIZE_T StackSize,
    SIZE_T MaximumStackSize,
    LPVOID pUnkown
    );
    #else
    typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    LPVOID ObjectAttributes,
    HANDLE ProcessHandle,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    BOOL CreateSuspended,
    DWORD dwStackSize,
    DWORD dw1,
    DWORD dw2,
    LPVOID pUnkown
    );
    #endif
    typedef_ZwCreateThreadEx ZwCreateThreadEx= NULL;
    ZwCreateThreadEx= (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdll, "ZwCreateThreadEx");
    if(ZwCreateThreadEx== NULL)
    {
    printf("[!] Get ZwCreateThreadEx Address Error,Error is:%d", GetLastError());
    return FALSE;
    }
    else
    {
    printf("[*] Get ZwCreateThreadEx Address Successfully! Address is %x", ZwCreateThreadEx);
    }
    HANDLE hRemoteThread;
    ZwRet= ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hprocess,
    (LPTHREAD_START_ROUTINE)pThreadFunction, pAlloc, 0, 0, 0, 0, NULL);
    if(hRemoteThread == NULL)
    {
    printf("[!] Creat RemoteThread Error,Error is:%d", GetLastError());
    CloseHandle(hprocess);
    return FALSE;
    }
    printf("[*] Please wait for a moment in the process of injection:");
    for(int m = 0;m<5;m++)
    {
    if(EnumModules(_Pid, psDllPath))
    {
    printf("[√] Creat RemoteThread Successfully! RemoteThread Id is %x", hRemoteThread);
    VirtualFreeEx(hprocess, pAlloc, 0, MEM_RELEASE);
    CloseHandle(hRemoteThread);
    CloseHandle(hprocess);
    FreeLibrary(hNtdll);
    return TRUE;
    }
    Sleep(2000);
    }
    printf("[!] DLL injection failed!Notice:Please check that your path is absolute or correct");
    VirtualFreeEx(hprocess, pAlloc, 0, MEM_RELEASE);
    CloseHandle(hRemoteThread);
    CloseHandle(hprocess);
    FreeLibrary(hNtdll);
    return FALSE;
    }
    int main(int argc, char* argv[])
    {
    if(argc == 3)
    {
    EnbalePrivileges(GetCurrentProcess(), SE_DEBUG_NAME);
    DWORD dwPid;
    sscanf(argv[1],"%d", &dwPid);
    _InjectThread(dwPid, argv[2]);
    return1;
    }
    else
    {
    printf("[!] You passed in the wrong number of parameters!Please pass in two parameters.");
    printf("[!] Notice:[!] The first parameter is the PID of the target process[!] The second parameter is the location of the injected DLL,Please enter the absolute path!");
    return0;
    }
    }
    

    直接注入,看到線程創建成功就表示已經成功了。

    img

    用procexp也可以看一眼。

    img

    比如現在我們想要結束QQ進程。

    img

    會發現無法結束。

    img

    這里由于還沒有寫判斷規則,這個任務管理器目前無法結束任何進程,也就是所有進程都無法結束,這顯然用戶體驗是不好的。

    那么如果要選擇性保護進程,又應該怎么做呢。注意TerminateProcess的第一個參數,傳入的是一個句柄,這個句柄需要從openprocess的返回值獲得,所以我們還需要知道打開進程的句柄。

    同一進程多次使用openprocess獲取的句柄是不一樣的。

    inline hook的穩定性還是差了點,很容易讓進程崩潰。根據實驗:任務管理器會不斷地調用openprocess這個api,不管有沒有操作都會一直調用。這里就用微軟更加穩定的detours庫。

    voidHook()
    {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    // 參數一是原函數地址,參數二是新函數地址
    DetourAttach((PVOID*)&OldOpenProcess, New_OpenProcess);
    DetourAttach((PVOID*)&OldTerminateProcess, New_TerminateProcess);
    DetourTransactionCommit();
    }
    voidUnHook()
    {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    // 和Hook完全一樣,不同的只是將DetourAttach換成DetourDetach
    DetourDetach((PVOID*)&OldTerminateProcess, New_TerminateProcess);
    DetourDetach((PVOID*)&OldOpenProcess, New_OpenProcess);
    DetourTransactionCommit();
    }
    

    我們自己的函數如下編寫,就是做一些簡單的判斷,比如這里要保護的進程id為5568 :

    HANDLE g_handle = NULL;
    HANDLE WINAPI New_OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId) {
    if(dwProcessId == 5568) {
            g_handle = OldOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    return g_handle;
    }
    else
    {
            HANDLE hHandle = OldOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    return hHandle;
    }
    }
    BOOL WINAPI New_TerminateProcess(
    _In_ HANDLE hProcess,
    _In_ UINT uExitCode
    ) {
    if(g_handle == hProcess)
    {
    MessageBox(NULL, L"該進程受保護!", L"Access Denied", NULL);
            g_handle = NULL;
    returnfalse;
    }
    else
    {
    OldTerminateProcess(hProcess, uExitCode);
    returntrue;
    }
    }
    

    printfdword
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    羊城杯 re wp
    2021-10-07 16:01:00
    題的質量還是可以,有些題因為遇到一些問題,沒解出來。花時間來寫wp一是鞏固一些知識點,還有讓更多的人可以互相學習。
    HEVD學習筆記——UAF
    2021-11-28 16:07:36
    這里選擇x86的驅動來進行黑盒測試學習內核漏洞,作為學習筆記記錄下來。
    EXP編寫學習之繞過GS
    2023-02-20 09:58:16
    棧中的守護天使 :GSGS原理向棧內壓入一個隨機的DWORD值,這個隨機數被稱為canary ,IDA稱為 Security Cookie。Security Cookie 放入 ebp前,并且data節中存放一個 Security Cookie的副本。棧中發生溢出時,Security Cookie首先被淹沒,之后才是ebp和返回地址。函數返回之前,會添加一個Security Cookie驗證操作,稱為Security Check。檢測到溢出時,系統將進入異常處理流程,函數不會正常返回,ret也不會被執行。函數使用無保護的關鍵字標記。緩沖區不是8字節類型 且 大小不大于4個字節。可以為函數強制啟用GS。
    0x01 進程遍歷因為進程是在隨時進行變動的所以我們需要獲取一張快照1.1 CreateToolhelp32
    前言在PE文件中,存在iat導入表,記錄了PE文件使用的API以及相關的dll模塊。可以看到使用了MessageBox這個API殺軟會對導入表進行查殺,如果發現存在惡意的API,比如VirtualAlloc,CreateThread等,就會認為文件是一個惡意文件。自定義API函數FARPROC GetProcAddress;定義:typedef int ();HMODULE LoadLibraryA; // 成功返回句柄 失敗返回NULL. 這里GetModuleHandle和LoadLibrary作用是一樣的,獲取dll文件。HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );printf; pMessageBox MyMessageBox = GetProcAddress; MyMessageBox; return 0;}. 程序可以正常運行:查看其導入表:User32.dll和MessageBox都不存在。實戰測試用創建進程的方式加載shellcode。
    最近粗淺的研究了一下Windows應用層相關調試API和對應調試原理,以達到實現反附加的功能。本文內容主要參考《軟件調試》和網絡上相關優秀文章,并且主要側重在應用層調試附加方面,關于內核層面因為水平有限本文沒有詳細展現。
    可在其中找受影響的版本復現,在受影響版本的系統中找到win32k.sys導入IDA。漏洞函數位于win32k.sys的SetImeInfoEx()函數,該函數在使用一個內核對象的字段之前并沒有進行是否為空的判斷,當該值為空時,函數直接讀取零地址內存。如果在當前進程環境中沒有映射零頁面,該函數將觸發頁面錯誤異常,導致系統藍屏發生。tagWINDOWSTATIONspklList對象的結構為:漏洞觸發驗證查看SSDT表dd KeServiceDescriptorTabledds Address L11C 顯示地址里面值指向的地址. 以4個字節顯示。
    全局鉤子注入-獲取QQ密碼實現 全局鉤子注入-獲取QQ密碼實現 水一篇????? SetWindowsHookExA 將應用程序定義的掛鉤過程安裝到掛鉤鏈中。您將安裝一個掛鉤程序來監視系統中某些類型的事件。這些事件與特定線程或與調用線程相同的桌面中的所有線程相關聯。
    一篇靜態免殺的文章
    2021安洵杯PWN WP詳解
    2021-12-29 16:41:08
    做了2021安洵杯線上賽題目,總體來說題目有簡單有難的,難易程度合適,這次就做了pwn,把四道pwn題思路總結一下,重點是沒幾個人做出來的最后一道pwnsky,賽后做了復現。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类