ShellCode应用

c++

Posted by YiMiTuMi on February 19, 2021

shellCold

1.ShellCode编写原则

  1) 不能有全局变量

  2) 不能使用常量字符串

char szBuffer[] = "ShellCode"; //会使用常量区,所以不可用

//写成
char szBuffer[] = {'S', 'h', 'e', 'l', '\0'}; //这个使用堆栈

char szBuffer[] = {'K', '0', 'e', '0', '\0'}; //UNICODE格式,高字节为零,占2个字符,一般函数名为UinCode格式

  3) 不能使用系统调用

//也会依赖导入表,不可用
HMODULE hMoudle = LoadLibrary("user32.dll");
GetProcAddress(hMoudle, "MessageBoxA");

可以获取 LoadLibrary 和 GetProcAddress的地址来使用。

  4) 不能嵌套调用其他函数

原因:不依赖环境,放到任何地方都可以执行的机器码。

将写好的ShellCode的机器码拿出他是一段放到哪里都可以执行的代码,不依赖任何环境。

#include <iostream>
#include <windows.h>

typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
}UNICODE_STRING, *PUNICODE_STRING;

typedef struct _PEB_LDR_DATA
{
	ULONG Length; // +0x00
	BOOLEAN Initialized; // +0x04
	PVOID SsHandle; // +0x08
	LIST_ENTRY InLoadOrderModuleList; // +0x0c
	LIST_ENTRY InMemoryOrderModuleList; // +0x14
	LIST_ENTRY InInitializationOrderModuleList;// +0x1c
    VOID* EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA; // +0x24

typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	WORD LoadCount;
	WORD TlsIndex;
	union
	{
		LIST_ENTRY HashLinks;
		struct
		{
			PVOID SectionPointer;
			ULONG CheckSum;
		};
	};
	union
	{
		ULONG TimeDateStamp;
		PVOID LoadedImports;
	};
	_ACTIVATION_CONTEXT* EntryPointActivationContext;
	PVOID PatchInformation;
	LIST_ENTRY ForwarderLinks;
	LIST_ENTRY ServiceTagLinks;
	LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;

typedef DWORD (WINAPI* PGetProcAddress) (_In_ HMODULE hModule, _In_ LPCSTR lpProcName);
typedef HMODULE (WINAPI* PLoadLibraryA) (_In_ LPCSTR lpLibFileName);
typedef int (WINAPI* PMessageBoxA) (_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText ,_In_opt_ LPCSTR lpCaption, _In_ UINT uType);

PMessageBoxA MessageBoxFun = NULL;
PGetProcAddress GetProAddrNameFun = NULL;
PLoadLibraryA LoadLibraryAFun = NULL;

//获取 LoadLibrary 和 GetProcAddress的函数地址 
void GetMoudleAddress()
{
	//LDR链
	PLDR_DATA_TABLE_ENTRY pLdr = NULL;
	PLDR_DATA_TABLE_ENTRY pBegLdr = NULL;
	DWORD dwKernel32Addr = 0;

    //不能使用常量字符串, UniCode格式
    //Kernel32.dll
    char szKernel32Name[] = {'K', 0, 'E', 0, 'R', 0, 'N', 0, 'E', 0,  'L', 0,  '3', 0, '2', 0, '.', 0, 'D', 0, 'L', 0, 'L', 0, 0, 0};
	//wchar_t szKernel32Name[] = { 'K', 'E', 'R',  'N', 'E', 'L', '3', '2', '.', 'D', 'L', 'L', 0};

    //GetProcAddress
    char szGetProAddrName[] = {'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0};

    //LoadLibrary
    char szLoadLibraryName[] = {'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0};

    //获取链表 TEB -> PEB -> _PEB_LDR_DATA -> _LDR_DATA_TABLE_ENTRY
	_asm
	{
		mov eax, fs:[0x30]      //PEB
		mov eax, [eax + 0x0c]   //PEB -> Ldr
		add eax, 0x0c           //LDR_DATA_TABLE_ENTRY -> InLoadOrderModuleList
		mov pBegLdr, eax        //获取 InLoadOrderModuleList 的地址
		mov eax, [eax]          
		mov pLdr, eax           //获取 InLoadOrderModuleList 的成员指针
	}

	//遍历处Kernerl32.dll的地址
	while (pLdr != pBegLdr)
	{
		WORD* pLast = (WORD*)pLdr->BaseDllName.Buffer;
		WORD* pFirst = (WORD*)szKernel32Name;

		//wprintf(L"%s \n", pLdr->BaseDllName.Buffer);

		//比较字符串
		while (*pFirst != 0 && *pFirst == *pLast)
		{
			pFirst++;
			pLast++;
		}

		if (*pFirst == *pLast)
		{
			dwKernel32Addr = (DWORD)pLdr->DllBase;
			break;
		}
		
		pLdr = (PLDR_DATA_TABLE_ENTRY)pLdr->InLoadOrderLinks.Flink;
	}

	//遍历PE导出表获取GetProcAddress和LoadLibrary的地址
	PIMAGE_DOS_HEADER pDos = NULL;
	PIMAGE_NT_HEADERS pNt = NULL;
	PIMAGE_FILE_HEADER pPe = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalPe = NULL;

	//获取DOS头
	pDos = (PIMAGE_DOS_HEADER)dwKernel32Addr;
	pNt = (PIMAGE_NT_HEADERS)((DWORD)dwKernel32Addr + pDos->e_lfanew);
	pPe = (PIMAGE_FILE_HEADER)((DWORD)pNt + 4);     //标准PE头
	pOptionalPe = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPe + IMAGE_SIZEOF_FILE_HEADER); //可选pe头

	//导出表
	PIMAGE_DATA_DIRECTORY pExportFunctionData = (PIMAGE_DATA_DIRECTORY)pOptionalPe->DataDirectory;
	PIMAGE_EXPORT_DIRECTORY pExportFunctionInfo = (PIMAGE_EXPORT_DIRECTORY)((DWORD)dwKernel32Addr + pExportFunctionData->VirtualAddress);
	
	DWORD* pAddofNames = (DWORD*)((DWORD)dwKernel32Addr + pExportFunctionInfo->AddressOfNames);
	WORD* pAddofOrd = (WORD*)((DWORD)dwKernel32Addr + pExportFunctionInfo->AddressOfNameOrdinals);
	DWORD* pAddofFun = (DWORD*)((DWORD)dwKernel32Addr + pExportFunctionInfo->AddressOfFunctions);

	DWORD dwCnt = 0;
	char* pFinded = NULL;
	char* pSrc = szGetProAddrName;

	for (; dwCnt < pExportFunctionInfo->NumberOfNames; dwCnt++)
	{
		pFinded = (char*)((DWORD)dwKernel32Addr + pAddofNames[dwCnt]);

		//printf("%s \n", pFinded);

		//判断名字
		while (*pSrc && *pSrc == *pFinded)
		{
			pSrc++;
			pFinded++;
		}

		if (*pSrc == *pFinded)
		{
			GetProAddrNameFun = (PGetProcAddress)((DWORD)dwKernel32Addr + pAddofFun[pAddofOrd[dwCnt]]);
			break;
		}

		pSrc = szGetProAddrName;
	}

	LoadLibraryAFun = (PLoadLibraryA)GetProAddrNameFun((HMODULE)dwKernel32Addr, szLoadLibraryName);

	return;
}

int main()
{
	GetMoudleAddress();
	
	//User32.dll
	char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0};
	//MessageBoxA
	char szMessageBoxA[] = {'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0};

	HMODULE hMessageBoxA = LoadLibraryAFun(szUser32);
	MessageBoxFun = (PMessageBoxA)GetProAddrNameFun(hMessageBoxA, szMessageBoxA);

	char szText[] = { 'T', 'e', 'x', 't', 0};
	char szTextt[] = { 'T', 'e', 'x', 't', 0 };

	MessageBoxFun(NULL, szText, szTextt, MB_OK);

	return 0;
}

蓝色妖姬 – 相守