1.Windows shellcode编写原则
- 1.字符串使用:字符串使用的时候不要使用双引号字符串,否则变量会放在常量区。字符串最后最好放一个
0x00
。 - 2.加载模块:加载模块从PEB获取当前进程空间
kernel32.dll
基址,然后遍历kernel32.dll的导出表获取LoadLibraryA
和GetProcAddress
函数地址。 - 3.项目属性中进行如下配置:
-
- C/C++ --> 常规 --> SDL检查:否
-
- C/C++ --> 优化 --> 优化 :最大优化(优化大小)
-
- C/C++ --> 代码生成 --> 安全检查 :禁用安全检查(/GS-)
-
- 链接器 --> 清单文件 --> 生成清单:否
-
- 链接器 --> 调试 --> 生成调试信息:否
-
- 链接器 --> 高级 --> 入口点 :自己重新定义个入口点函数名称
2.编译后生成代码的顺序
注意一定要让shellcode的入口点在提取到的shellcode最前面。
- 1.同文件中:同文件中,多个函数按照实现顺序排序
- 2.不同文件中:不同文件中,按照如下图所示,项目配置文件中的顺序进行排序
3.代码样例
以下代码中实现了一段执行messageBox的shellcode。代码如下:
#include <windows.h> #include <winternl.h> typedef struct detail_LDR_DATA_TABLE_ENTRY{ LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; DWORD SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; }detail_LDR_DATA_TABLE_ENTRY,*Pdetail_LDR_DATA_TABLE_ENTRY; typedef HMODULE (WINAPI *pLoadLibraryA)(_In_ LPCSTR lpLibFileName); typedef WINBASEAPI FARPROC (WINAPI *pGetProcAddress)(_In_ HMODULE hModule,_In_ LPCSTR lpProcName); typedef int (WINAPI* pMessageBoxA)(_In_opt_ HWND hWnd,_In_opt_ LPCSTR lpText,_In_opt_ LPCSTR lpCaption,_In_ UINT uType); void* getFuncAddrFromKernel32(char* targetFuncName); int test() { //从kernel32中获取loadLibrary和GetProcAddress char loadLibraryAName[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0x00 }; void* loadLibraryFuncAddr = getFuncAddrFromKernel32(loadLibraryAName); char getProcAddrName[] = { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s',0x00 };; void* GetProcAddressFuncAddr = getFuncAddrFromKernel32(getProcAddrName); //调用LoadLibraryA加载想用的dll pLoadLibraryA myLoadLibrary = (pLoadLibraryA)loadLibraryFuncAddr; char dllName[] = { 'u','s','e','r','3','2','\.','d','l','l',0x00 }; HMODULE user32Handler = myLoadLibrary(dllName); //调用GetProcAddress获取方法地址 char funcName[] = { 'M','e','s','s','a','g','e','B','o','x','A',0x00 }; pGetProcAddress myGetProcAddress = (pGetProcAddress)GetProcAddressFuncAddr; //调用目标方法 pMessageBoxA myMessageBoxA = pMessageBoxA(myGetProcAddress(user32Handler, funcName)); char title[] = { 't','i','t','l','e',0x00 }; char msg[] = { 'm','e','s','s','a','g','e',0x00 }; myMessageBoxA(NULL, msg, title, NULL); return 0; } void* getFuncAddrFromKernel32(char* targetFuncName) { //获取PEB指针 PPEB pebPtr = (PPEB)__readfsdword(0x0C * sizeof(PVOID)); //获取PEB结构块的PEB_LDR_DATA PPEB_LDR_DATA pldr = pebPtr->Ldr; //链表头节点、尾节点; PLIST_ENTRY pListEntryNow = NULL; PLIST_ENTRY pListEntryEnd = NULL; pListEntryNow = pldr->InMemoryOrderModuleList.Flink; pListEntryEnd = pldr->InMemoryOrderModuleList.Flink; Pdetail_LDR_DATA_TABLE_ENTRY pNowLdrDataEntry = NULL; PIMAGE_DOS_HEADER kernel32Base = NULL;//用于保存kernel32的基址 //循环遍历以加载模块 do { pNowLdrDataEntry = (Pdetail_LDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntryNow, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); wchar_t name[] = { 'K','E','R','N','E','L','3','2',0x00 }; DWORD res = 0; wchar_t* BaseDllName = NULL; BaseDllName = (wchar_t*)pNowLdrDataEntry->BaseDllName.Buffer; //对比dll名称 wchar_t* psrc = name; wchar_t* pdst = BaseDllName; res = 1; while (*psrc) { if (*psrc != *pdst) { res = 0; break; } else { psrc++; pdst++; } } if (res != 0) { kernel32Base = (PIMAGE_DOS_HEADER)pNowLdrDataEntry->DllBase; break; } pListEntryNow = pNowLdrDataEntry->InMemoryOrderLinks.Flink; } while (1); //获取kernerl32 NT头 PIMAGE_NT_HEADERS kernel32IMAGE_NT_HEADERS = NULL; kernel32IMAGE_NT_HEADERS = PIMAGE_NT_HEADERS(((char*)kernel32Base) + kernel32Base->e_lfanew); //获取导出表RVA IMAGE_DATA_DIRECTORY pExportImgDataDir = kernel32IMAGE_NT_HEADERS->OptionalHeader.DataDirectory[0]; //获取导出表 PIMAGE_EXPORT_DIRECTORY pimgExportDir = (PIMAGE_EXPORT_DIRECTORY)((char*)kernel32Base + pExportImgDataDir.VirtualAddress); int targetFuncIndexAddressOfNames = NULL; //遍历导出名称表,获取序号 for (int i = 0; i < pimgExportDir->NumberOfNames; i++) { PDWORD nameAddr = (PDWORD)((DWORD)kernel32Base + pimgExportDir->AddressOfNames); char* currentName = (char*)kernel32Base + nameAddr[i]; ////printf("正在对比:%s\n", currentName); char* psrc = targetFuncName; char* pdst = currentName; DWORD res = 1; while (*psrc) { if (*psrc != *pdst) { res = 0; break; } else { psrc++; pdst++; } } if (res != 0) { targetFuncIndexAddressOfNames = i; break; } } //根据函数序号表查函数序号表 int targetFuncIndexInAddressOfNameOrdinals = NULL; if (targetFuncIndexAddressOfNames != NULL) { PWORD AddressOfNameOrdinals = (PWORD)((DWORD)kernel32Base + pimgExportDir->AddressOfNameOrdinals); targetFuncIndexInAddressOfNameOrdinals = AddressOfNameOrdinals[targetFuncIndexAddressOfNames]; } PVOID targetFuncAddr = NULL; //根据序号查函数地址表获取函数地址 if (targetFuncIndexInAddressOfNameOrdinals) { PDWORD AddressOfFunctions = (PDWORD)((DWORD)kernel32Base + pimgExportDir->AddressOfFunctions); targetFuncAddr = (PVOID)((DWORD)kernel32Base + AddressOfFunctions[targetFuncIndexInAddressOfNameOrdinals]); } return targetFuncAddr; }
编译后的代码中,直接使用winhex提取text段即可。
然后复制到加载器中测试即可。