-
-
[原创]Win PE系列之导出表解析与ShellCode的编写及应用
-
2021-10-12 16:38 11042
-
一.导出表解析
编写dll文件的目的是在dll文件中实现一些函数功能,以供其他程序使用。而导出表的作用就是用来告诉操作系统所到处的函数的信息,好让其他程序可以方便的调用导出函数。
导出表保存的地址在数据目录的第一项保存着,在文档中有如下的定义
typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; // 导出表文件名称RVA DWORD Base; // 导出函数起始序号 DWORD NumberOfFunctions; // 所有的导出函数的个数 DWORD NumberOfNames; // 以函数名字导出的函数个数 DWORD AddressOfFunctions; // 导出函数地址数组的RVA DWORD AddressOfNames; // 函数名称地址数组的RVA DWORD AddressOfNameOrdinals; // 序号地址数组的RVA } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
Name字段保存的是文件名的字符串的RVA,通过它可以找到dll文件的文件名,那么就可以使用LoadLibrary来将dll文件加载进内存。
最关键的三个成员就是最后三个成员,它们分别保存了指向特定的三个数组的RVA,如下图所示
AddressOfFunctions指向的是整型数组,数组的个数由NumberOfFunctions来确定,如果数组元素的内容非0,那它就是一个导出函数的地址。
AddressOfNames指向的也是一个整型数组,数组里面保存的是相应的函数名称的RVA,数组个数由NumberOfNames确定。
AddressOfNameOrdinals指向的是短整型数组,数组里面保存的是序号
上面根据Name字段找到dll的文件名以后,使用LoadLibrary将dll文件加载进内存,而为了找到相应的函数地址,还需要使用GetProcAddress函数来得到函数地址,而GetProcAddress函数可以使用字符串和序号的方式来获得函数地址。·
对于字符串的方式,首先是去AddressOfNames得到各个字符串的地址,然后在字符串的地址中找到相应的字符串,和GetProcAddress函数传入的字符串做比较,如果相等,则记录下这个相等的数组的下标,根据这个下标去AddressOfNameOrdinals中查找对应的下标中的序号值,得到的值就是作为数组AddressOfFunctions的索引来找到相应的函数地址。
另外一种是根据导出序号来查找函数,这个时候,GetProcAddress函数会首先将序号减去Base的值,得到AddressOfFunctions数组的索引,在根据这个索引来获得对应的函数的地址。
相应的导出表解析的代码如下
void PEParse::PrintExportTable() { char *pDllName = NULL, *pFunName = NULL; DWORD dwNumOfFun = 0, dwNumOfName = 0, i = 0; PDWORD pNameArr = NULL, pFunArr = NULL; PWORD pOrderArr = NULL; if (this->pExportTable == NULL) { printf("The file does not have export file.\n"); goto exit; } printf("=========================The Export Information=========================="); //获取dll的名称 pDllName = (char *)((DWORD)this->pDosHead + this->RVAToFOA(this->pExportTable->Name)); printf("The Dll name is %s\n", pDllName); //获取三个数组地址 pNameArr = (PDWORD)((DWORD)this->pDosHead + this->RVAToFOA(this->pExportTable->AddressOfNames)); pOrderArr = (PWORD)((DWORD)this->pDosHead + this->RVAToFOA(this->pExportTable->AddressOfNameOrdinals)); pFunArr = (PDWORD)((DWORD)this->pDosHead + this->RVAToFOA(this->pExportTable->AddressOfFunctions)); //获取以名字作为导出函数的个数 dwNumOfName = this->pExportTable->NumberOfNames; printf("print function address by AddressOfNames\n"); for (i = 0; i < dwNumOfName; i++) { pFunName = (char *)this->pDosHead + this->RVAToFOA(pNameArr[i]); //得到函数名称的地址 printf("The function name is %s\n", pFunName); //根据函数名称的下标到序号表中得到函数数组的索引 printf("The function address is 0x%X\n", this->RVAToFOA(pFunArr[pOrderArr[i]])); } //获取导出函数的总个数 dwNumOfFun = this->pExportTable->NumberOfFunctions; printf("print function address by AddressOfFunctions\n"); for (i = 0; i < dwNumOfFun; i++) { if (pFunArr[i]) //如果不是0,说明里面保存的是函数地址RVA { printf("The function address is 0x%X\n", this->RVAToFOA(pFunArr[i])); } } printf("=========================The Export Information==========================\n"); exit:; }
运行结果如下图
二.ShellCode的编写
所谓的ShellCode就是一段可以在任何情况下都能正常运行的机器码。那么为了这段机器码在任何时候都能运行就需要遵循下面的三个原则
不能使用全局变量,因为这些变量只在本进程有,其他进程空间中没有
不能嵌套调用其他函数,原因如上
不能调用系统函数,不同程序导入表内容是不一样
要解决上面的问题
对于字符串赋值要用char szTest = { 't', 'e', 's', 't', 0 }代替szTest = {"test"}
从遍历模块找到KERNEL32中,从它的导出表的GetProcAddress的地址,以此来导入需要的函数来调用
据此可以写出下列的ShellCode函数
#include <cstdio> #include <Windows.h> #define TOUPPER(x) (x >= 'a' && x <= 'z' ? x - 32 : x) typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; }UNICODE_STRING, *PUNICODE_STRING; typedef struct _PEB_LDR_DATA { DWORD Length; BOOL Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; }PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID DllBase; PVOID EntryPoint; UINT32 SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; UINT32 Flags; USHORT LoadCount; USHORT TlsIndex; LIST_ENTRY HashLinks; PVOID SectionPointer; UINT32 CheckSum; UINT32 TimeDateStamp; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation; }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; typedef FARPROC(WINAPI *pFnGetProcAddress)(HMODULE, LPCSTR); typedef HMODULE(WINAPI *pFnLoadLibrary)(LPCTSTR); typedef int(WINAPI *pFnMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT); VOID WINAPI ShellCode(); int main() { ShellCode(); return 0; } VOID WINAPI ShellCode() { HINSTANCE hKernel = NULL, hUser32 = NULL; char szKernel32[] = { '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 }; char szGetProc[] = { '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 szUser32[] = { 'u', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 }; char szMessageBox[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 }; char szOutput[] = { '1', '9', '0', '0', 0 }; PPEB_LDR_DATA ldr; PLDR_DATA_TABLE_ENTRY ldte; PLIST_ENTRY Head, Cur; pFnGetProcAddress myGetProcAddress = NULL; pFnLoadLibrary myLoadLibrary; pFnMessageBox myMessageBox; PWORD pKernel, pDllName; BOOL isFind; DWORD i, j; PIMAGE_DOS_HEADER pDosHead; PIMAGE_OPTIONAL_HEADER pOptionHead; PIMAGE_EXPORT_DIRECTORY pExport; DWORD dwAddrNumOfName; PDWORD pAddrOfName; PDWORD pAddrFunc; PWORD pAddrOfOrd; PCHAR pFuncName; __asm { push eax push ecx mov eax, fs:[0x30] mov ecx, [eax + 0x0C] mov ldr, ecx pop ecx pop eax } Head = &(ldr->InMemoryOrderModuleList); Cur = Head->Flink; pKernel = (PWORD)szKernel32; //遍历模块找到kernel32.dll模块的基地址 do { ldte = CONTAINING_RECORD(Cur, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList); pDllName = (PWORD)ldte->BaseDllName.Buffer; isFind = TRUE; for (i = 0; pKernel[i]; i++) { if (pKernel[i] != TOUPPER(pDllName[i])) //比较模块名字与目标模块名字是否相同 { isFind = FALSE; break; } } if (pDllName[i]) isFind = FALSE; if (isFind) { hKernel = (HINSTANCE)ldte->DllBase; //相同则找到需要的模块 break; } Cur = Cur->Flink; } while (Cur != Head); if (hKernel) //从导出表中获取GetProcAddress的地址 { pDosHead = (PIMAGE_DOS_HEADER)hKernel; pOptionHead = (PIMAGE_OPTIONAL_HEADER)((DWORD)pDosHead + pDosHead->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER); pExport = (PIMAGE_EXPORT_DIRECTORY)(pOptionHead->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (DWORD)pDosHead); dwAddrNumOfName = pExport->NumberOfFunctions; pAddrOfName = (PDWORD)((DWORD)pDosHead + pExport->AddressOfNames); pAddrFunc = (PDWORD)(pExport->AddressOfFunctions + (DWORD)hKernel); pAddrOfOrd = (PWORD)(pExport->AddressOfNameOrdinals + (DWORD)hKernel); for (i = 0; i < dwAddrNumOfName; i++) { pFuncName = (PCHAR)(pAddrOfName[i] + (DWORD)hKernel); isFind = TRUE; for ( j = 0; pFuncName[j]; j++) { if (pFuncName[j] != szGetProc[j]) { isFind = FALSE; break; } } if (szGetProc[j]) isFind = FALSE; if (isFind) { myGetProcAddress = (pFnGetProcAddress)(pAddrFunc[pAddrOfOrd[i]] + (DWORD)hKernel); break; } } } if (myGetProcAddress) //得到GetProcAddress以后可以获得需要的系统函数 { myLoadLibrary = (pFnLoadLibrary)myGetProcAddress(hKernel, szLoadLibrary); hUser32 = myLoadLibrary(szUser32); if (hUser32) { myMessageBox = (pFnMessageBox)myGetProcAddress(hUser32, szMessageBox); myMessageBox(0, szOutput, szOutput, 0); } } }
提取出相应的ShellCode如下
unsigned char szShellcode[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0xF8, 0x00, 0x00, 0x00, 0x53, 0x56, 0x57, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x45, 0xDC, 0x4B, 0xC6, 0x45, 0xDD, 0x00, 0xC6, 0x45, 0xDE, 0x45, 0xC6, 0x45, 0xDF, 0x00, 0xC6, 0x45, 0xE0, 0x52, 0xC6, 0x45, 0xE1, 0x00, 0xC6, 0x45, 0xE2, 0x4E, 0xC6, 0x45, 0xE3, 0x00, 0xC6, 0x45, 0xE4, 0x45, 0xC6, 0x45, 0xE5, 0x00, 0xC6, 0x45, 0xE6, 0x4C, 0xC6, 0x45, 0xE7, 0x00, 0xC6, 0x45, 0xE8, 0x33, 0xC6, 0x45, 0xE9, 0x00, 0xC6, 0x45, 0xEA, 0x32, 0xC6, 0x45, 0xEB, 0x00, 0xC6, 0x45, 0xEC, 0x2E, 0xC6, 0x45, 0xED, 0x00, 0xC6, 0x45, 0xEE, 0x44, 0xC6, 0x45, 0xEF, 0x00, 0xC6, 0x45, 0xF0, 0x4C, 0xC6, 0x45, 0xF1, 0x00, 0xC6, 0x45, 0xF2, 0x4C, 0xC6, 0x45, 0xF3, 0x00, 0xC6, 0x45, 0xF4, 0x00, 0xC6, 0x45, 0xF5, 0x00, 0xC6, 0x45, 0xCC, 0x47, 0xC6, 0x45, 0xCD, 0x65, 0xC6, 0x45, 0xCE, 0x74, 0xC6, 0x45, 0xCF, 0x50, 0xC6, 0x45, 0xD0, 0x72, 0xC6, 0x45, 0xD1, 0x6F, 0xC6, 0x45, 0xD2, 0x63, 0xC6, 0x45, 0xD3, 0x41, 0xC6, 0x45, 0xD4, 0x64, 0xC6, 0x45, 0xD5, 0x64, 0xC6, 0x45, 0xD6, 0x72, 0xC6, 0x45, 0xD7, 0x65, 0xC6, 0x45, 0xD8, 0x73, 0xC6, 0x45, 0xD9, 0x73, 0xC6, 0x45, 0xDA, 0x00, 0xC6, 0x45, 0xBC, 0x4C, 0xC6, 0x45, 0xBD, 0x6F, 0xC6, 0x45, 0xBE, 0x61, 0xC6, 0x45, 0xBF, 0x64, 0xC6, 0x45, 0xC0, 0x4C, 0xC6, 0x45, 0xC1, 0x69, 0xC6, 0x45, 0xC2, 0x62, 0xC6, 0x45, 0xC3, 0x72, 0xC6, 0x45, 0xC4, 0x61, 0xC6, 0x45, 0xC5, 0x72, 0xC6, 0x45, 0xC6, 0x79, 0xC6, 0x45, 0xC7, 0x41, 0xC6, 0x45, 0xC8, 0x00, 0xC6, 0x45, 0xB0, 0x75, 0xC6, 0x45, 0xB1, 0x73, 0xC6, 0x45, 0xB2, 0x65, 0xC6, 0x45, 0xB3, 0x72, 0xC6, 0x45, 0xB4, 0x33, 0xC6, 0x45, 0xB5, 0x32, 0xC6, 0x45, 0xB6, 0x2E, 0xC6, 0x45, 0xB7, 0x64, 0xC6, 0x45, 0xB8, 0x6C, 0xC6, 0x45, 0xB9, 0x6C, 0xC6, 0x45, 0xBA, 0x00, 0xC6, 0x45, 0xA4, 0x4D, 0xC6, 0x45, 0xA5, 0x65, 0xC6, 0x45, 0xA6, 0x73, 0xC6, 0x45, 0xA7, 0x73, 0xC6, 0x45, 0xA8, 0x61, 0xC6, 0x45, 0xA9, 0x67, 0xC6, 0x45, 0xAA, 0x65, 0xC6, 0x45, 0xAB, 0x42, 0xC6, 0x45, 0xAC, 0x6F, 0xC6, 0x45, 0xAD, 0x78, 0xC6, 0x45, 0xAE, 0x41, 0xC6, 0x45, 0xAF, 0x00, 0xC6, 0x45, 0x9C, 0x31, 0xC6, 0x45, 0x9D, 0x39, 0xC6, 0x45, 0x9E, 0x30, 0xC6, 0x45, 0x9F, 0x30, 0xC6, 0x45, 0xA0, 0x00, 0xC7, 0x45, 0x88, 0x00, 0x00, 0x00, 0x00, 0x50, 0x51, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x8B, 0x48, 0x0C, 0x89, 0x4D, 0x98, 0x59, 0x58, 0x8B, 0x45, 0x98, 0x83, 0xC0, 0x14, 0x89, 0x45, 0x90, 0x8B, 0x45, 0x90, 0x8B, 0x08, 0x89, 0x4D, 0x8C, 0x8D, 0x45, 0xDC, 0x89, 0x85, 0x7C, 0xFF, 0xFF, 0xFF, 0x8B, 0x45, 0x8C, 0x83, 0xE8, 0x08, 0x89, 0x45, 0x94, 0x8B, 0x45, 0x94, 0x8B, 0x48, 0x30, 0x89, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x7C, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x85, 0xD2, 0x0F, 0x84, 0x84, 0x00, 0x00, 0x00, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x61, 0x7C, 0x30, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x7A, 0x7F, 0x1B, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xEA, 0x20, 0x89, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0xEB, 0x16, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x89, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x7C, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x3B, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0x74, 0x0C, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x05, 0xE9, 0x55, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x85, 0xD2, 0x74, 0x0A, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x83, 0xBD, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x0B, 0x8B, 0x45, 0x94, 0x8B, 0x48, 0x18, 0x89, 0x4D, 0xFC, 0xEB, 0x14, 0x8B, 0x45, 0x8C, 0x8B, 0x08, 0x89, 0x4D, 0x8C, 0x8B, 0x45, 0x8C, 0x3B, 0x45, 0x90, 0x0F, 0x85, 0xE4, 0xFE, 0xFF, 0xFF, 0x83, 0x7D, 0xFC, 0x00, 0x0F, 0x84, 0x79, 0x01, 0x00, 0x00, 0x8B, 0x45, 0xFC, 0x89, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x3C, 0x8B, 0x95, 0x68, 0xFF, 0xFF, 0xFF, 0x8D, 0x44, 0x0A, 0x18, 0x89, 0x85, 0x64, 0xFF, 0xFF, 0xFF, 0xB8, 0x08, 0x00, 0x00, 0x00, 0x6B, 0xC8, 0x00, 0x8B, 0x95, 0x64, 0xFF, 0xFF, 0xFF, 0x8B, 0x44, 0x0A, 0x60, 0x03, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x89, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x14, 0x89, 0x8D, 0x5C, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x68, 0xFF, 0xFF, 0xFF, 0x03, 0x48, 0x20, 0x89, 0x8D, 0x58, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x1C, 0x03, 0x4D, 0xFC, 0x89, 0x8D, 0x54, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x24, 0x03, 0x4D, 0xFC, 0x89, 0x8D, 0x50, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x3B, 0x85, 0x5C, 0xFF, 0xFF, 0xFF, 0x0F, 0x83, 0xC4, 0x00, 0x00, 0x00, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x58, 0xFF, 0xFF, 0xFF, 0x8B, 0x14, 0x81, 0x03, 0x55, 0xFC, 0x89, 0x95, 0x4C, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x4C, 0xFF, 0xFF, 0xFF, 0x03, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x08, 0x85, 0xC9, 0x74, 0x2C, 0x8B, 0x85, 0x4C, 0xFF, 0xFF, 0xFF, 0x03, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x08, 0x8B, 0x95, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x44, 0x15, 0xCC, 0x3B, 0xC8, 0x74, 0x0C, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x02, 0xEB, 0xB2, 0x8B, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x4C, 0x05, 0xCC, 0x85, 0xC9, 0x74, 0x0A, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x83, 0xBD, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x21, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x50, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x8B, 0x85, 0x54, 0xFF, 0xFF, 0xFF, 0x8B, 0x0C, 0x90, 0x03, 0x4D, 0xFC, 0x89, 0x4D, 0x88, 0xEB, 0x05, 0xE9, 0x1B, 0xFF, 0xFF, 0xFF, 0x83, 0x7D, 0x88, 0x00, 0x74, 0x3B, 0x8D, 0x45, 0xBC, 0x50, 0x8B, 0x4D, 0xFC, 0x51, 0xFF, 0x55, 0x88, 0x89, 0x45, 0x84, 0x8D, 0x45, 0xB0, 0x50, 0xFF, 0x55, 0x84, 0x89, 0x45, 0xF8, 0x83, 0x7D, 0xF8, 0x00, 0x74, 0x1D, 0x8D, 0x45, 0xA4, 0x50, 0x8B, 0x4D, 0xF8, 0x51, 0xFF, 0x55, 0x88, 0x89, 0x45, 0x80, 0x6A, 0x00, 0x8D, 0x45, 0x9C, 0x50, 0x8D, 0x4D, 0x9C, 0x51, 0x6A, 0x00, 0xFF, 0x55, 0x80, 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3};
三.ShellCode的使用
这里通过新增一个节来把ShellCode写入这个新增节,在修改程序的入口来在程序执行前先执行ShellCode。
新增节的步骤如下
检测节头的间隙是否够容纳下一个节头
申请足够的空间容纳原文件和ShellCode及跳转指令
填充要跳转回去的地址到Jmp
将原文件内容和ShellCode以及跳转指令复制到申请的空间中
将新增节的属性加入节表
增加FILE_HEADER中的NumberOfSections
修改OPTIONAL_HEADER中的AddressOfEntryPoint和SizeOfImage
将内容保存到一个文件中
具体实现代码如下
bool PEParse::AddSection() { unsigned char szShellcode[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0xF8, 0x00, 0x00, 0x00, 0x53, 0x56, 0x57, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x45, 0xDC, 0x4B, 0xC6, 0x45, 0xDD, 0x00, 0xC6, 0x45, 0xDE, 0x45, 0xC6, 0x45, 0xDF, 0x00, 0xC6, 0x45, 0xE0, 0x52, 0xC6, 0x45, 0xE1, 0x00, 0xC6, 0x45, 0xE2, 0x4E, 0xC6, 0x45, 0xE3, 0x00, 0xC6, 0x45, 0xE4, 0x45, 0xC6, 0x45, 0xE5, 0x00, 0xC6, 0x45, 0xE6, 0x4C, 0xC6, 0x45, 0xE7, 0x00, 0xC6, 0x45, 0xE8, 0x33, 0xC6, 0x45, 0xE9, 0x00, 0xC6, 0x45, 0xEA, 0x32, 0xC6, 0x45, 0xEB, 0x00, 0xC6, 0x45, 0xEC, 0x2E, 0xC6, 0x45, 0xED, 0x00, 0xC6, 0x45, 0xEE, 0x44, 0xC6, 0x45, 0xEF, 0x00, 0xC6, 0x45, 0xF0, 0x4C, 0xC6, 0x45, 0xF1, 0x00, 0xC6, 0x45, 0xF2, 0x4C, 0xC6, 0x45, 0xF3, 0x00, 0xC6, 0x45, 0xF4, 0x00, 0xC6, 0x45, 0xF5, 0x00, 0xC6, 0x45, 0xCC, 0x47, 0xC6, 0x45, 0xCD, 0x65, 0xC6, 0x45, 0xCE, 0x74, 0xC6, 0x45, 0xCF, 0x50, 0xC6, 0x45, 0xD0, 0x72, 0xC6, 0x45, 0xD1, 0x6F, 0xC6, 0x45, 0xD2, 0x63, 0xC6, 0x45, 0xD3, 0x41, 0xC6, 0x45, 0xD4, 0x64, 0xC6, 0x45, 0xD5, 0x64, 0xC6, 0x45, 0xD6, 0x72, 0xC6, 0x45, 0xD7, 0x65, 0xC6, 0x45, 0xD8, 0x73, 0xC6, 0x45, 0xD9, 0x73, 0xC6, 0x45, 0xDA, 0x00, 0xC6, 0x45, 0xBC, 0x4C, 0xC6, 0x45, 0xBD, 0x6F, 0xC6, 0x45, 0xBE, 0x61, 0xC6, 0x45, 0xBF, 0x64, 0xC6, 0x45, 0xC0, 0x4C, 0xC6, 0x45, 0xC1, 0x69, 0xC6, 0x45, 0xC2, 0x62, 0xC6, 0x45, 0xC3, 0x72, 0xC6, 0x45, 0xC4, 0x61, 0xC6, 0x45, 0xC5, 0x72, 0xC6, 0x45, 0xC6, 0x79, 0xC6, 0x45, 0xC7, 0x41, 0xC6, 0x45, 0xC8, 0x00, 0xC6, 0x45, 0xB0, 0x75, 0xC6, 0x45, 0xB1, 0x73, 0xC6, 0x45, 0xB2, 0x65, 0xC6, 0x45, 0xB3, 0x72, 0xC6, 0x45, 0xB4, 0x33, 0xC6, 0x45, 0xB5, 0x32, 0xC6, 0x45, 0xB6, 0x2E, 0xC6, 0x45, 0xB7, 0x64, 0xC6, 0x45, 0xB8, 0x6C, 0xC6, 0x45, 0xB9, 0x6C, 0xC6, 0x45, 0xBA, 0x00, 0xC6, 0x45, 0xA4, 0x4D, 0xC6, 0x45, 0xA5, 0x65, 0xC6, 0x45, 0xA6, 0x73, 0xC6, 0x45, 0xA7, 0x73, 0xC6, 0x45, 0xA8, 0x61, 0xC6, 0x45, 0xA9, 0x67, 0xC6, 0x45, 0xAA, 0x65, 0xC6, 0x45, 0xAB, 0x42, 0xC6, 0x45, 0xAC, 0x6F, 0xC6, 0x45, 0xAD, 0x78, 0xC6, 0x45, 0xAE, 0x41, 0xC6, 0x45, 0xAF, 0x00, 0xC6, 0x45, 0x9C, 0x31, 0xC6, 0x45, 0x9D, 0x39, 0xC6, 0x45, 0x9E, 0x30, 0xC6, 0x45, 0x9F, 0x30, 0xC6, 0x45, 0xA0, 0x00, 0xC7, 0x45, 0x88, 0x00, 0x00, 0x00, 0x00, 0x50, 0x51, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x8B, 0x48, 0x0C, 0x89, 0x4D, 0x98, 0x59, 0x58, 0x8B, 0x45, 0x98, 0x83, 0xC0, 0x14, 0x89, 0x45, 0x90, 0x8B, 0x45, 0x90, 0x8B, 0x08, 0x89, 0x4D, 0x8C, 0x8D, 0x45, 0xDC, 0x89, 0x85, 0x7C, 0xFF, 0xFF, 0xFF, 0x8B, 0x45, 0x8C, 0x83, 0xE8, 0x08, 0x89, 0x45, 0x94, 0x8B, 0x45, 0x94, 0x8B, 0x48, 0x30, 0x89, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x7C, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x85, 0xD2, 0x0F, 0x84, 0x84, 0x00, 0x00, 0x00, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x61, 0x7C, 0x30, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xFA, 0x7A, 0x7F, 0x1B, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x83, 0xEA, 0x20, 0x89, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0xEB, 0x16, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x89, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x7C, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x3B, 0x95, 0x08, 0xFF, 0xFF, 0xFF, 0x74, 0x0C, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x05, 0xE9, 0x55, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x78, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x85, 0xD2, 0x74, 0x0A, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x83, 0xBD, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x0B, 0x8B, 0x45, 0x94, 0x8B, 0x48, 0x18, 0x89, 0x4D, 0xFC, 0xEB, 0x14, 0x8B, 0x45, 0x8C, 0x8B, 0x08, 0x89, 0x4D, 0x8C, 0x8B, 0x45, 0x8C, 0x3B, 0x45, 0x90, 0x0F, 0x85, 0xE4, 0xFE, 0xFF, 0xFF, 0x83, 0x7D, 0xFC, 0x00, 0x0F, 0x84, 0x79, 0x01, 0x00, 0x00, 0x8B, 0x45, 0xFC, 0x89, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x3C, 0x8B, 0x95, 0x68, 0xFF, 0xFF, 0xFF, 0x8D, 0x44, 0x0A, 0x18, 0x89, 0x85, 0x64, 0xFF, 0xFF, 0xFF, 0xB8, 0x08, 0x00, 0x00, 0x00, 0x6B, 0xC8, 0x00, 0x8B, 0x95, 0x64, 0xFF, 0xFF, 0xFF, 0x8B, 0x44, 0x0A, 0x60, 0x03, 0x85, 0x68, 0xFF, 0xFF, 0xFF, 0x89, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x14, 0x89, 0x8D, 0x5C, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x68, 0xFF, 0xFF, 0xFF, 0x03, 0x48, 0x20, 0x89, 0x8D, 0x58, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x1C, 0x03, 0x4D, 0xFC, 0x89, 0x8D, 0x54, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x60, 0xFF, 0xFF, 0xFF, 0x8B, 0x48, 0x24, 0x03, 0x4D, 0xFC, 0x89, 0x8D, 0x50, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x3B, 0x85, 0x5C, 0xFF, 0xFF, 0xFF, 0x0F, 0x83, 0xC4, 0x00, 0x00, 0x00, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x58, 0xFF, 0xFF, 0xFF, 0x8B, 0x14, 0x81, 0x03, 0x55, 0xFC, 0x89, 0x95, 0x4C, 0xFF, 0xFF, 0xFF, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x8B, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0x01, 0x89, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x8B, 0x85, 0x4C, 0xFF, 0xFF, 0xFF, 0x03, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x08, 0x85, 0xC9, 0x74, 0x2C, 0x8B, 0x85, 0x4C, 0xFF, 0xFF, 0xFF, 0x03, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x08, 0x8B, 0x95, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x44, 0x15, 0xCC, 0x3B, 0xC8, 0x74, 0x0C, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x02, 0xEB, 0xB2, 0x8B, 0x85, 0x6C, 0xFF, 0xFF, 0xFF, 0x0F, 0xBE, 0x4C, 0x05, 0xCC, 0x85, 0xC9, 0x74, 0x0A, 0xC7, 0x85, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x83, 0xBD, 0x74, 0xFF, 0xFF, 0xFF, 0x00, 0x74, 0x21, 0x8B, 0x85, 0x70, 0xFF, 0xFF, 0xFF, 0x8B, 0x8D, 0x50, 0xFF, 0xFF, 0xFF, 0x0F, 0xB7, 0x14, 0x41, 0x8B, 0x85, 0x54, 0xFF, 0xFF, 0xFF, 0x8B, 0x0C, 0x90, 0x03, 0x4D, 0xFC, 0x89, 0x4D, 0x88, 0xEB, 0x05, 0xE9, 0x1B, 0xFF, 0xFF, 0xFF, 0x83, 0x7D, 0x88, 0x00, 0x74, 0x3B, 0x8D, 0x45, 0xBC, 0x50, 0x8B, 0x4D, 0xFC, 0x51, 0xFF, 0x55, 0x88, 0x89, 0x45, 0x84, 0x8D, 0x45, 0xB0, 0x50, 0xFF, 0x55, 0x84, 0x89, 0x45, 0xF8, 0x83, 0x7D, 0xF8, 0x00, 0x74, 0x1D, 0x8D, 0x45, 0xA4, 0x50, 0x8B, 0x4D, 0xF8, 0x51, 0xFF, 0x55, 0x88, 0x89, 0x45, 0x80, 0x6A, 0x00, 0x8D, 0x45, 0x9C, 0x50, 0x8D, 0x4D, 0x9C, 0x51, 0x6A, 0x00, 0xFF, 0x55, 0x80, 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D}; bool bRes = true; DWORD dwFileAlignment = this->pOptionHead->FileAlignment, dwSectionAlignment = this->pOptionHead->SectionAlignment; DWORD dwSize = 0; void *pDestMemory = NULL; PIMAGE_DOS_HEADER pDosHead = NULL; PIMAGE_FILE_HEADER pFileHead = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHead = NULL; PIMAGE_SECTION_HEADER pDestSectionHead = NULL; HANDLE hFile = NULL; DWORD dwRet = 0; unsigned char szJmp[5] = { 0xE9, 0, 0, 0, 0 }; //跳转回原位置 if (this->pSectionHead[0].PointerToRawData - ((DWORD)&this->pSectionHead[this->pFileHead->NumberOfSections - 1] - (DWORD)this->pDosHead) < 2 * IMAGE_SIZEOF_SECTION_HEADER) { printf("间隙不够\n"); bRes = false; goto exit; } dwSize = this->pSectionHead[this->pFileHead->NumberOfSections - 1].PointerToRawData + this->pSectionHead[this->pFileHead->NumberOfSections - 1].SizeOfRawData + this->Align(sizeof(szShellcode) + sizeof(szJmp), dwFileAlignment); pDestMemory = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (pDestMemory == NULL) { this->ShowError("VirtualAlloc"); bRes = false; goto exit; } //将原有代码写入 memcpy(pDestMemory, (void *)this->pDosHead, this->pSectionHead[this->pFileHead->NumberOfSections - 1].PointerToRawData + this->pSectionHead[this->pFileHead->NumberOfSections - 1].SizeOfRawData); pDosHead = (PIMAGE_DOS_HEADER)pDestMemory; pFileHead = (PIMAGE_FILE_HEADER)((DWORD)pDosHead + pDosHead->e_lfanew + 4); pOptionHead = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHead + IMAGE_SIZEOF_FILE_HEADER); pDestSectionHead = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHead + pFileHead->SizeOfOptionalHeader); //填充执行完ShellCode以后要跳转回去的位置 *(PDWORD)(szJmp + 1) = this->pOptionHead->AddressOfEntryPoint - (pDestSectionHead[pFileHead->NumberOfSections - 1].VirtualAddress + this->Align(pDestSectionHead[pFileHead->NumberOfSections - 1].Misc.VirtualSize, dwSectionAlignment) + sizeof(szShellcode) + 5); //将新代码加入 memcpy((void *)((DWORD)pDestMemory + pDestSectionHead[pFileHead->NumberOfSections - 1].PointerToRawData + pDestSectionHead[pFileHead->NumberOfSections - 1].SizeOfRawData), szShellcode, sizeof(szShellcode)); memcpy((void *)((DWORD)pDestMemory + pDestSectionHead[pFileHead->NumberOfSections - 1].PointerToRawData + pDestSectionHead[pFileHead->NumberOfSections - 1].SizeOfRawData + sizeof(szShellcode)), szJmp, sizeof(szJmp)); //增加节表 ZeroMemory((void *)&pDestSectionHead[pFileHead->NumberOfSections], IMAGE_SIZEOF_SECTION_HEADER); memcpy(pDestSectionHead[pFileHead->NumberOfSections].Name, ".1900", strlen(".1900")); pDestSectionHead[pFileHead->NumberOfSections].PointerToRawData = pDestSectionHead[pFileHead->NumberOfSections - 1].PointerToRawData + this->Align(pDestSectionHead[pFileHead->NumberOfSections - 1].SizeOfRawData, dwFileAlignment); pDestSectionHead[pFileHead->NumberOfSections].SizeOfRawData = this->Align(sizeof(szShellcode) + sizeof(szJmp), dwFileAlignment); pDestSectionHead[pFileHead->NumberOfSections].VirtualAddress = pDestSectionHead[pFileHead->NumberOfSections - 1].VirtualAddress + this->Align(pDestSectionHead[pFileHead->NumberOfSections - 1].Misc.VirtualSize, dwSectionAlignment); pDestSectionHead[pFileHead->NumberOfSections].Misc.VirtualSize = this->Align(sizeof(szShellcode) + sizeof(szJmp), dwSectionAlignment); pDestSectionHead[pFileHead->NumberOfSections].Characteristics |= IMAGE_SCN_MEM_EXECUTE; pFileHead->NumberOfSections++; //增加节数量 pOptionHead->AddressOfEntryPoint = pDestSectionHead[pFileHead->NumberOfSections - 1].VirtualAddress; pOptionHead->SizeOfImage += this->Align(sizeof(szShellcode) + sizeof(szJmp), dwSectionAlignment); //增加SizeOfImage hFile = CreateFile( "dest.exe", //get file handle //打开目标文件并保存 GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { this->ShowError("CreateFile"); bRes = false; goto exit; } if (!WriteFile(hFile, pDestMemory, dwSize, &dwRet, NULL)) { this->ShowError("WriteFile"); bRes = false; goto exit; } exit: if (hFile) CloseHandle(hFile); if (pDestMemory) { if (!VirtualFree(pDestMemory, 0, MEM_DECOMMIT)) { this->ShowError("VirtualFree"); } } return bRes; }
最终生成的程序就会在运行代码前先执行ShellCode的代码
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界