天天看點

對CreateRemoteThread的使用

本人小白水準,内容中有看不懂的地方請直接在留言中詢問,如果代碼中有錯誤或者用法不正确的地方還請立刻指出,本人QQ号 : 3216393922

對于 CreateRemoteThread,比較簡單的用法是用LoadLibrary在目标程序中注入dll,也可以在遠端線程中注入代碼,并将它運作,不過,有一下幾個注意點:

1、如何在遠端線程中調用字元串?

所有的字元串必須在目标程序的位址空間中,是以我在目标程序内開辟了兩個空間,一個用來存放代碼,一個用來存放資料。将資料打包成結構體REMOTE_DATA,一次性運到目标程序中去,再将該結構體資料在目标程序中的位址作為線程函數的參數,這樣就可以線上程函數中調用結構體中的字元串資料。
           

2、如何在遠端線程中任意調用系統函數?

為了在遠端線程中可以調用任何想調用的函數,必須擁有LoadLibraryW和GetProcAddress這兩個函數,調用某一個函數時,先用LoadLibraryW得到函數所在的dll子產品句柄,再用GetProcAddress得到函數位址。
           

例如:想要在遠端線程函數内調用MessageBoxW函數,它在User32.dll中

先在資料結構體中定義函數名和dll名

CHAR szMessageBoxW[20] = “MessageBoxW”;

WCHAR szUser32[20] = TEXT(“user32.dll”);

再在遠端線程函數中得到dll子產品句柄

HMODULE hUser32 = LOADLIBRARYW(myData->szUser32);

然後申明MessageBoxW函數

typedef int(WINAPI* Func1)(HWND hwnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

Func1 MESSAGEBOXW = (Func1)GETPROCADDRESS(hUser32, myData->szMessageBoxW);

最後調用MessageBoxW函數

MESSAGEBOXW(NULL, myData->szText, myData->szCaption, MB_OK);

3、如何得到函數代碼在記憶體中的大小?

#pragma check_stack(off)
void test()
{
    //你的代碼
}
void AfterFunc()
{
    return;
}
#pragma check_stack
           

調用SIZE_T cbSize = ((BYTE )(DWORD)AfterFunc - (BYTE )(DWORD)RemoteThreadFunc) + 10就可以得到函數test()的大小,該方法在Debug下無法使用,在Release中才可以使用。

目标是在程序PEView.exe中建立一個線程,線程中建立一個MessageBoxW

下面是代碼:

#include <Windows.h>
#include <TlHelp32.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <Psapi.h>
using namespace std;

//1.定義程序名稱
const wstring& wsProcessName = TEXT("PEView.exe");

//2.定義遠端線程中使用的資料
typedef struct
{
    WCHAR szCaption[] = TEXT("123");
    WCHAR szText[] = TEXT("456");

    //2.1需要使用的dll
    WCHAR szKernel32[] = TEXT("kernel32.dll");
    WCHAR szUser32[] = TEXT("user32.dll");
    WCHAR szGdi32[] = TEXT("gdi32.dll");

    //2.2需要使用的函數
    CHAR szMessageBoxW[] = "MessageBoxW";
    CHAR szLoadCursorW[] = "LoadCursorW";
    CHAR szSetCursor[] = "SetCursor";
    CHAR szSleep[] = "Sleep";

    //2.3兩個函數LoadLibraryW和GetProcAddressW的位址
    DWORD dwLoadLibraryW = ;
    DWORD dwGetProcAddress = ;

}REMOTE_DATA, *PREMOTE_DATA;
REMOTE_DATA remoteData;

//3.定義遠端線程的函數
#pragma check_stack(off)
DWORD __stdcall RemoteThreadFunc(PREMOTE_DATA myData)
{
    //LoadLibraryW-->LOADLIBRARYW
    typedef HMODULE(WINAPI* LoadLibraryWFunc)(
        LPCWSTR lpFileName
        );
    LoadLibraryWFunc LOADLIBRARYW = (LoadLibraryWFunc)myData->dwLoadLibraryW;
    //GetProcAddress-->GETPROCADDRESS
    typedef FARPROC(WINAPI* GetProcAddressFunc)(
        HMODULE hModule,
        LPCSTR lpProcName
        );
    GetProcAddressFunc GETPROCADDRESS = (GetProcAddressFunc)myData->dwGetProcAddress;

    //加載hUser32.dll并得到其句柄
    HMODULE hKernel32 = LOADLIBRARYW(myData->szKernel32);
    HMODULE hUser32 = LOADLIBRARYW(myData->szUser32);
    HMODULE hGdi32 = LOADLIBRARYW(myData->szGdi32);

    //調用MessageBoxW
    typedef int(WINAPI* Func1)(
        HWND hwnd,
        LPCWSTR lpText,
        LPCWSTR lpCaption,
        UINT uType
        );
    Func1 MESSAGEBOXW = (Func1)GETPROCADDRESS(hUser32, myData->szMessageBoxW);
    MESSAGEBOXW(NULL, myData->szText, myData->szCaption, MB_OK);

    return ;
}
void AfterFunc()
{
    return;
}
#pragma check_stack

BOOL AdjustProcessTokenPrivilege()
{
    LUID luidTmp;
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        return FALSE;
    }

    if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidTmp))
    {
        ::CloseHandle(hToken);
        return FALSE;
    }

    tkp.PrivilegeCount = ;
    tkp.Privileges[].Luid = luidTmp;
    tkp.Privileges[].Attributes = SE_PRIVILEGE_ENABLED;

    if (!::AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
        ::CloseHandle(hToken);
        return FALSE;
    }

    return TRUE;
}
BOOL Camp2str(wstring wsStrA, wstring wsStrB)
{
    int nSize = wsStrA.length();
    for (int i = ; i < nSize; ++i)
    {
        if (wsStrA[i] >= 'A'&&wsStrA[i] <= 'Z')
            wsStrA[i] += 'a' - 'A';
    }
    nSize = wsStrB.length();
    for (int i = ; i < nSize; ++i)
    {
        if (wsStrB[i] >= 'A'&&wsStrB[i] <= 'Z')
            wsStrB[i] += 'a' - 'A';
    }

    return wsStrA == wsStrB;
}
DWORD GetProcessIdByName(const wstring& wsProcessName)
{
    HANDLE hProcess = ;
    DWORD dwProcess[], dwNeeded;
    TCHAR tcProcName[MAX_PATH] = {  };
    wstring wsNowProcessName = L"";
    int nTempSize = ;
    int nPos = ;

    //将所有程序的ID儲存在數組dwProcess中,共dwNeeded個程序
    EnumProcesses(dwProcess, sizeof(dwProcess), &dwNeeded);

    //用ID打開每一個程序
    for (int i = ; i < (dwNeeded / sizeof(DWORD)); ++i)
    {
        if (dwProcess[i] != )
        {
            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcess[i]);
            GetModuleFileNameEx(hProcess, NULL, tcProcName, MAX_PATH);
            nPos = wstring(tcProcName).find_last_of(L'\\');
            if (nPos != wstring::npos)
            {
                wsNowProcessName = wstring(wstring(tcProcName).substr(nPos + ));
                if (Camp2str(wsProcessName, wsNowProcessName))
                {
                    DWORD aa = dwProcess[i];
                    return aa;
                }
            }
        }

    }

    return ;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    //1.提權
    if (!AdjustProcessTokenPrivilege())
    {
        MessageBox(NULL, TEXT("無法提升權限"), TEXT("Fail"), MB_ICONERROR);
        return -;
    }

    DWORD dwProID = ;
    HANDLE hProcess = NULL;
    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
    HANDLE hThread = NULL;
    void* pRemoteData = NULL;
    void* pRemoteThread = NULL;

    __try
    {
        //2.擷取程序ID dwProPID
        if ((dwProID = GetProcessIdByName(wsProcessName)) == )
        {
            MessageBox(NULL, TEXT("無法由程序名找到程序"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }

        //3.打開程序句柄hProcess
        if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProID)) == NULL)
        {
            MessageBox(NULL, TEXT("無法打開程序"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }

        //4.在宿主程序中找到LoadLibraryW函數和GetProcAddressW函數的位址
        //并分别賦給remoteData.dwLoadLibraryW和remoteData.dwGetProcAddress
        MODULEENTRY32W me32 = { sizeof(MODULEENTRY32W) };
        hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProID);
        if (hModuleSnap == INVALID_HANDLE_VALUE)
        {
            MessageBox(NULL, TEXT("無法擷取子產品快照"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }
        if (!Module32FirstW(hModuleSnap, &me32))
        {
            MessageBox(NULL, TEXT("無法擷取子產品快照"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }
        do
        {
            //找到目标程序中的Kernel32.dll
            if (lstrcmpiW(me32.szModule, TEXT("Kernel32.dll"))==)
            {
                //獲得本地hKernel32.dll或LoadLibraryW或GetProcAddress的位址
                HANDLE hKernel32 = GetModuleHandleW(TEXT("Kernel32.dll"));
                DWORD loadlibraryw = (DWORD)GetProcAddress((HMODULE)hKernel32, (LPCSTR)"LoadLibraryW");
                DWORD getprocaddress = (DWORD)GetProcAddress((HMODULE)hKernel32, (LPCSTR)"GetProcAddress");
                if (hKernel32 == NULL || loadlibraryw ==  || getprocaddress == )
                {
                    MessageBox(NULL, TEXT("無法獲得本地hKernel32.dll或LoadLibraryW或GetProcAddress的位址"), TEXT("Fail"), MB_ICONERROR);
                    __leave;
                }

                //獲得目标程序hKernel32.dll或LoadLibraryW或GetProcAddress的位址
                remoteData.dwLoadLibraryW = loadlibraryw - (DWORD)hKernel32 + (DWORD)me32.hModule;
                remoteData.dwGetProcAddress = getprocaddress - (DWORD)hKernel32 + (DWORD)me32.hModule;
                break;
            }
        } while (Module32NextW(hModuleSnap, &me32));
        CloseHandle(hModuleSnap);
        hModuleSnap = INVALID_HANDLE_VALUE;
        if (remoteData.dwLoadLibraryW ==  || remoteData.dwGetProcAddress == )
        {
            MessageBox(NULL, TEXT("未能在目标程序中找到kernel32.dll"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }

        //5.1在宿主程序裡配置設定記憶體,用于存參數remoteData
        pRemoteData = VirtualAllocEx(hProcess, NULL, sizeof(remoteData), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if (pRemoteData == NULL)
        {
            MessageBox(NULL, TEXT("無法在宿主程序中配置設定記憶體"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }
        //5.2把remoteData寫入到目标程序的記憶體pRemoteData中去
        if (!WriteProcessMemory(hProcess, pRemoteData, &remoteData, sizeof(remoteData), NULL))
        {
            MessageBox(NULL, TEXT("無法将資料remoteData寫入宿主程序中"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }
        //6.1在宿主程序裡配置設定記憶體,用于寫線程函數RemoteThreadFunc
        SIZE_T cbSize = ((BYTE *)(DWORD)AfterFunc - (BYTE *)(DWORD)RemoteThreadFunc) + ;
        if (cbSize <= )
        {
            cbSize = ;
        }
        pRemoteThread = VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (pRemoteThread == NULL)
        {
            MessageBox(NULL, TEXT("無法在宿主程序中配置設定記憶體"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }
        //6.2.把RemoteThread指向的函數寫入到目标程序的記憶體pRemoteThread中去
        if (!WriteProcessMemory(hProcess, pRemoteThread, &RemoteThreadFunc, cbSize, NULL))
        {
            MessageBox(NULL, TEXT("無法将線程函數RemoteThread寫入宿主程序中"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }

        //7.啟動注入宿主程序的線程
        hThread = CreateRemoteThread(hProcess, NULL, , (LPTHREAD_START_ROUTINE)pRemoteThread, pRemoteData, , NULL);
        if (!hThread)
        {
            MessageBox(NULL, TEXT("無法在宿主程序中建立遠端線程"), TEXT("Fail"), MB_ICONERROR);
            __leave;
        }

        //8.等待線程結束,然後清理記憶體
        WaitForSingleObject(hThread, INFINITE);
    }
    __finally
    {
        if (hProcess != NULL)
        {
            CloseHandle(hProcess);
        }
        if (hModuleSnap != INVALID_HANDLE_VALUE)
        {
            CloseHandle(hModuleSnap);
        }
        if (hThread != NULL)
        {
            CloseHandle(hThread);
        }
        if (pRemoteThread != NULL)
        {
            VirtualFreeEx(hProcess, pRemoteThread, , MEM_RELEASE);
        }
        if (pRemoteData != NULL)
        {
            VirtualFreeEx(hProcess, pRemoteData, , MEM_RELEASE);
        }
    }

    return ;
}
           

繼續閱讀