ShellCode注入
程序员文章站
2024-02-12 10:40:46
...
注意点:
1. 不能有全局变量
2. 不能使用常量字符串 ,可以使用这种形式 szTitle = {'a', 'b', 'c', 0};
3. 不能使用系统调用,比如不能直接使用MessageBox,因为生成的汇编是 Call [0xxxxxx],这个0xxxxx是导入表的地址,注入的程序导入表地址不同而且导入表中不一定有这个函数,可以使用LoadLibrary配合GetProcAddress,但是LoadLibrary和GetProcAddress也是系统调用,也依赖导入表需要通过PEB的模块链,找到Kernel32.dll的模块句柄,然后找到Kernel32.dll的导出表,然后找到LoadLibrary和GetProcAddress的函数地址
4. 不能嵌套调用其他函数,注入后函数地址变化了
头文件,结构体定义
#pragma once
#include <windows.h>
typedef struct _UNICODE_STR
{
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STR ImagePathName;
UNICODE_STR CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB_LDR_DATA
{
DWORD dwLength; //结构体大小
DWORD dwInitialized; //进程是否初始化完成
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
//PEB
typedef struct __PEB
{
BYTE Reserved1[2];
BYTE BeingDebugged;
#ifdef _WIN64
BYTE Reserved2[21];
#else
BYTE Reserved2[9];
#endif
PPEB_LDR_DATA pLdr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved3[520];
BYTE Reserved4[136];
ULONG SessionId;
} _PEB, *_PPEB;
cpp文件
#include "ShellCode.h"
typedef PVOID(__stdcall *MyGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
typedef HMODULE(__stdcall *MyLoadLibraryA)(LPCSTR lpLibFileName);
typedef int (__stdcall *MyMessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);
void ShellCode()
{
//获取peb地址 fs:[0x30]
#ifdef _WIN64
DWORD64 dwPeb = __readgsqword(0x60);
#else
DWORD dwPeb = __readfsdword(0x30);
#endif
//unicode格式
wchar_t szKernel32[] = { L'K', L'E', L'R', L'N' , L'E' , L'L' , L'3' , L'2' , L'.', L'D', L'L', L'L', 0, 0 };
char szUser32[] = { 'U', 'S', 'E', 'R', '3', '2', '.', 'D', 'L', 'L', 0 };
char szGetProcAddr[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0 };
char szLoadLibrary[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0 };
char szMessageBox[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };
PVOID pKernelBase = nullptr;
MyGetProcAddress pMyGetProcAddress = nullptr;
//遍历Dll模块
PLDR_DATA_TABLE_ENTRY pDataTable = (PLDR_DATA_TABLE_ENTRY)((PPEB_LDR_DATA)((_PPEB)dwPeb)->pLdr)->InMemoryOrderModuleList.Flink;
while (pDataTable)
{
//找到kernel32模块
LPTSTR lpDllName = (LPTSTR)pDataTable->BaseDllName.pBuffer;
wchar_t* pTemp = szKernel32;
while (*pTemp && *pTemp == *lpDllName)
{
pTemp++;
lpDllName++;
}
if (*pTemp == 0)
{
pKernelBase = pDataTable->DllBase;
break;
}
//双向链表的下一个
pDataTable = (PLDR_DATA_TABLE_ENTRY)pDataTable->InMemoryOrderModuleList.Flink;
}
if (pKernelBase == nullptr)
{
return;
}
//定位到PE指纹
UINT_PTR pSignature = (UINT_PTR)pKernelBase + ((PIMAGE_DOS_HEADER)pKernelBase)->e_lfanew;
//定位到导出表
UINT_PTR pExportTable = (UINT_PTR)&((PIMAGE_NT_HEADERS)pSignature)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
pExportTable = (UINT_PTR)pKernelBase + ((PIMAGE_DATA_DIRECTORY)pExportTable)->VirtualAddress;
//函数名表
UINT_PTR pNameArray = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfNames;
//函数地址表
UINT_PTR pAddressArray = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfFunctions;
//函数序号表
UINT_PTR pNameOrdinals = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfNameOrdinals;
//导出函数个数
DWORD dwExportFunCount = ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->NumberOfNames;
//遍历导出函数
for (int i = 0; i < dwExportFunCount; i++)
{
//导出函数名
char* pFunName = (char*)((UINT_PTR)pKernelBase + ((UINT_PTR*)pNameArray)[i]);
//找到GetProcAddress
char* pTemp = szGetProcAddr;
while (*pTemp && *pTemp == *pFunName)
{
pTemp++;
pFunName++;
}
if (*pTemp == 0)
{
//从序号表中取出地址表中的索引
unsigned int nIndex = ((unsigned short*)pNameOrdinals)[i];
//根据索引获取函数地址
pMyGetProcAddress = MyGetProcAddress((UINT_PTR)pKernelBase + ((UINT_PTR*)pAddressArray)[nIndex]);
break;
}
}
//用GetProcAddress获取到LoadLibraryA的地址
MyLoadLibraryA pMyLoadLibraryA = (MyLoadLibraryA)pMyGetProcAddress((HMODULE)pKernelBase, szLoadLibrary);
HMODULE hUser32 = pMyLoadLibraryA(szUser32);
MyMessageBoxA pMyMessageBox = (MyMessageBoxA)pMyGetProcAddress(hUser32, szMessageBox);
pMyMessageBox(0, 0, 0, 0);
}
int main()
{
ShellCode();
}
上一篇: 动态路由及RIP协议扩展配置等
下一篇: shellcode搜集