安全矩阵

 找回密码
 立即注册
搜索
查看: 4511|回复: 0

ShellCode生成框架

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-11-8 08:47:19 | 显示全部楼层 |阅读模式
原文链接:ShellCode生成框架

这里先写个简单的静态加载到exe文件中,明天再来写个动态的

因为vs编译后自己会生成很多东西,我们稍微配置下


先获取kernel32基址
  1. __declspec(naked) DWORD getKernel32()
  2. {
  3.   __asm
  4.   {
  5.     mov eax, fs:[30h]  //PEB
  6.       mov eax, [eax + 0ch]  //PEB->Ldr
  7.       mov eax, [eax + 14h]  //PEB->Ldr.InMemOrder
  8.       mov eax, [eax]  //第二个模块
  9.       mov eax, [eax]  //第三个模块
  10.       mov eax, [eax + 10h]  //base address
  11.       ret
  12.   }
  13. }
复制代码

获取GetProcAddress函数地址
  1. FARPROC  getProcAddress(HMODULE hModuleBase)
  2. {
  3.   PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
  4.   PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
  5.   if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
  6.   {
  7.     return NULL;
  8.   }
  9.   if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
  10.   {
  11.     return NULL;
  12.   }
  13.   PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  14.   PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
  15.   PWORD lpwOrd = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
  16.   PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);
  17.   DWORD dwLoop = 0;
  18.   FARPROC pRet = NULL;
  19.   for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++)
  20.   {
  21.     char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);
  22.     if (pFunName[0] == 'G' &&
  23.       pFunName[1] == 'e' &&
  24.       pFunName[2] == 't' &&
  25.       pFunName[3] == 'P' &&
  26.       pFunName[4] == 'r' &&
  27.       pFunName[5] == 'o' &&
  28.       pFunName[6] == 'c' &&
  29.       pFunName[7] == 'A' &&
  30.       pFunName[8] == 'd' &&
  31.       pFunName[9] == 'd' &&
  32.       pFunName[10] == 'r' &&
  33.       pFunName[11] == 'e' &&
  34.       pFunName[12] == 's' &&
  35.       pFunName[13] == 's')
  36.     {
  37.       pRet = (FARPROC)(lpdwFunAddr[lpwOrd[dwLoop]] + (DWORD)hModuleBase);
  38.       break;
  39.     }
  40.   }
  41.   return pRet;
  42. }
复制代码
首先定义ms-dos头
  1. //some code……
  2. PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
复制代码
然后得到pe头image-nt-header
  1. //some code……
  2. PIMAGE_NT_HEADERS32 lpNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)hModuleBase + lpDosHeader->e_lfanew);
复制代码
直接dos头加e_lfanew,这里因为是c++代码就不用汇编写入偏移地址3c等等,后面也要贴上汇编代码,结合一起看其实也不难理解
  1. //some code……
  2. if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
  3.   {
  4.     return NULL;
  5.   }
  6.   if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
  7.   {
  8.     return NULL;
  9.   }
复制代码

这里还是贴上这个图(转载的图)



在pe-option-header里面存在一个size和virualaddress,我们还是主要看 VirtualAddress(相对虚拟地址)字段,我们得到这个结构体
  1. //some code……
  2. PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase + (DWORD)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
复制代码
我们将会使用这个结构的如下字段:
AddressOfFunctions:指向一个DWORD类型的数组,每个数组元素指向一个函数地址。AddressOfNames:指向一个DWORD类型的数组,每个数组元素指向一个函数名称的字符串。AddressOfNameOrdinals:指向一个WORD类型的数组,每个数组元素表示相应函数的排列序号(16位整数)
  1. //some code……
  2. PDWORD lpdwFunName = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNames);
  3.   PWORD lpwOrd = (PWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfNameOrdinals);
  4.   PDWORD lpdwFunAddr = (PDWORD)((DWORD)hModuleBase + (DWORD)lpExports->AddressOfFunctions);
复制代码
然后判断是否为GetProcAddress函数是就返回
  1. //some code……
  2. DWORD dwLoop = 0;
  3.   FARPROC pRet = NULL;
  4.   for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++)
  5.   {
  6.     char* pFunName = (char*)(lpdwFunName[dwLoop] + (DWORD)hModuleBase);
  7.     if (pFunName[0] == 'G' &&
  8.       pFunName[1] == 'e' &&
  9.       pFunName[2] == 't' &&
  10.       pFunName[3] == 'P' &&
  11.       pFunName[4] == 'r' &&
  12.       pFunName[5] == 'o' &&
  13.       pFunName[6] == 'c' &&
  14.       pFunName[7] == 'A' &&
  15.       pFunName[8] == 'd' &&
  16.       pFunName[9] == 'd' &&
  17.       pFunName[10] == 'r' &&
  18.       pFunName[11] == 'e' &&
  19.       pFunName[12] == 's' &&
  20.       pFunName[13] == 's')
  21.     {
  22.       pRet = (FARPROC)(lpdwFunAddr[lpwOrd[dwLoop]] + (DWORD)hModuleBase);
  23.       break;
  24.     }
  25.   }
  26.   return pRet;
复制代码
这里用到了导出表里面得一个single每次查找一次就+1这里返回回去就是-1然后逐一进行判断
头部再定义一下
  1. //some code……
  2. DWORD getKernel32();
  3. FARPROC  getProcAddress(HMODULE hModuleBase);
复制代码

这里kernel32.dll和GetProcess函数地址都得到了后面就好说了
这里我们举CreateFile和Messagebox例子
这里是原来应该得写法
  1. //some code……
  2. typedef HANDLE(WINAPI *FN_CreateFileA)(
  3.     _In_ LPCSTR lpFileName,
  4.     _In_ DWORD dwDesiredAccess,
  5.     _In_ DWORD dwShareMode,
  6.     _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  7.     _In_ DWORD dwCreationDisposition,
  8.     _In_ DWORD dwFlagsAndAttributes,
  9.     _In_opt_ HANDLE hTemplateFile
  10.     );
  11.   FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)GetProcAddress(LoadLibraryA("kernel32.dll"), "CreateFileA");
复制代码

我们先处理LoadLibraryA("kernel32.dll")
先得到GetProcAddress
  1. typedef FARPROC(WINAPI * FN_GetProcAddress)(
  2.     _In_ HMODULE hModule,
  3.     _In_ LPCSTR lpProcName
  4.     );
  5.   FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());
复制代码
然后把"CreateFileA"字符串替换了
  1. char szCreateFile[] = { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'A',0 };
复制代码

这里完整为
  1. typedef FARPROC(WINAPI * FN_GetProcAddress)(
  2.     _In_ HMODULE hModule,
  3.     _In_ LPCSTR lpProcName
  4.     );
  5.   FN_GetProcAddress fn_GetProcAddress = (FN_GetProcAddress)getProcAddress((HMODULE)getKernel32());
  6.   typedef HANDLE(WINAPI *FN_CreateFileA)(
  7.     _In_ LPCSTR lpFileName,
  8.     _In_ DWORD dwDesiredAccess,
  9.     _In_ DWORD dwShareMode,
  10.     _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  11.     _In_ DWORD dwCreationDisposition,
  12.     _In_ DWORD dwFlagsAndAttributes,
  13.     _In_opt_ HANDLE hTemplateFile
  14.     );
  15.   char szCreateFile[] = { 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'A',0 };
  16.   FN_CreateFileA fn_CreateFileA = (FN_CreateFileA)fn_GetProcAddress((HMODULE)getKernel32(), szCreateFile);
  17.   char szNewFile[] = { '1', '.', 't', 'x', 't', '\0' };
  18.   fn_CreateFileA(szNewFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
复制代码
下面为MessageBoxA

  1. typedef HMODULE (WINAPI* FN_LoadLibraryA)(
  2.     _In_ LPCSTR lpLibFileName
  3.     );
  4.     char szLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0 };
  5.     FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress((HMODULE)getKernel32(), szLoadLibraryA);
  6.   typedef int (WINAPI* FN_MessageBoxA)(
  7.     _In_opt_ HWND hWnd,
  8.     _In_opt_ LPCSTR lpText,
  9.     _In_opt_ LPCSTR lpCaption,
  10.     _In_ UINT uType);
  11.   //正常写法
  12.   //FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
  13.   char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
  14.   char szMessageboxA[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };
  15.   FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(fn_LoadLibraryA(szUser32), szMessageboxA);
  16.   char szHello[] = { 'y', 'i', 'c', 'u', 'n', 'y', 'i', 'y', 'e', 0 };
  17.   char szTip[] = { 't', 'i', 'p', 0 };
  18.   fn_MessageBoxA(NULL, szHello, szTip, MB_OK);
复制代码
看看正常写法
  1. FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
复制代码
因为获取得是user32.dll而不是直接一样得kernel32.dll所以我们要获取下LoadLibraryA得地址
  1. typedef HMODULE (WINAPI* FN_LoadLibraryA)(
  2.     _In_ LPCSTR lpLibFileName
  3.     );
  4.     char szLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0 };
  5.     FN_LoadLibraryA fn_LoadLibraryA = (FN_LoadLibraryA)fn_GetProcAddress((HMODULE)getKernel32(), szLoadLibraryA);
复制代码
然后就是获取MessageBoxA得地址
  1. typedef int (WINAPI* FN_MessageBoxA)(
  2.     _In_opt_ HWND hWnd,
  3.     _In_opt_ LPCSTR lpText,
  4.     _In_opt_ LPCSTR lpCaption,
  5.     _In_ UINT uType);
  6.   //正常写法
  7.   //FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
  8.   char szUser32[] = { 'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0 };
  9.   char szMessageboxA[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };
  10.   FN_MessageBoxA fn_MessageBoxA = (FN_MessageBoxA)fn_GetProcAddress(fn_LoadLibraryA(szUser32), szMessageboxA);
复制代码
最后再输出
  1. char szHello[] = { 'y', 'i', 'c', 'u', 'n', 'y', 'i', 'y', 'e', 0 };
  2.   char szTip[] = { 't', 'i', 'p', 0 };
  3.   fn_MessageBoxA(NULL, szHello, szTip, MB_OK);
复制代码

运行结果可以看到没什么问题


然后我们peid打开

看下偏移是400然后我们ue打开然后找到对应得偏移地址复制这个16进制就是我们需要的shellcode,然后把shellcode插入到进程中执行就可以了,这里我们可以静态得插入到未执行得exe文件中,或者动态的插入到正在执行得进程的内存中,这里我们试试插入到未执行的exe文件中
  1. 558BEC83EC4C56E8E40000008BC8E8FD0000008BF0C745D0437265618D45D0C745D47465466950C745D86C654100E8BD00000050FFD66A006A006A026A006A0068000000408D4DF4C745F4312E74785166C745F87400FFD08D45B4C745B44C6F616450C745B84C696272C745BC61727941C645C000E87600000050FFD68D4DC4C745DC55736572518D4DDCC745E033322E645166C745E46C6CC645E600C745C44D657373C745C861676542C745CC6F784100FFD050FFD66A008D4DFCC745E879696375518D4DE8C745EC6E796979516A0066C745F06500C745FC74697000FFD033C05E8BE55DC3CCCCCCCCCCCCCCCCCC64A1300000008B400C8B40148B008B008B4010C3CCCCCCCCCCCCCCCCCCCCCCCC558BEC8BD183EC088B423C837C107C00750633C08BE55DC38B44107885C074F28B4C102403CA538B5C1020894DFC03DA8B4C101C568B74101803CA57894DF833FF33C94E8B048B03C2803847754E80780165754880780274754280780350753C8078047275368078056F753080780663752A80780741752480780864751E80780964751880780A72751280780B65750C80780C73750680780D73740E413BCE76A38BC75F5E5B8BE55DC38B45FC8B7DF80FB704488B3C8703FA8BC75F5E5B8BE55DC30000
复制代码

这里是29行+4个,我用以前写的端口扫描做测试

先看看入口的文件偏移

000C23A0然后用winhex打开
然后我们转到偏移地址

修改同样大小他shellcode替换了,所以只要运行这个exe就会运行我们的shellcode

然后我们保存运行

说明我们的shellcode插入了这个exe中,执行他就执行了我们的shellcode
我们也可以把他shellcode生成为一个bin文件再写个加载器运行








回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 12:40 , Processed in 0.014498 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表