看流星社区

 找回密码
 注册账号
查看: 2378|回复: 0

分享一个简短的内存加载DLL EXE

[复制链接]

该用户从未签到

发表于 2019-6-17 14:32:15 | 显示全部楼层 |阅读模式

实现类似功能的代码很多,但是我这份没有参考到别人的代码,纯粹是看微软文档撸出来的。这个需求是源于我的一个比较复杂的x86_64 shellcode,需要实现的功能很多,依赖也很多。因此用传统的方法弄的shellcode很不方便。于是我想着直接用dll/exe当作shellcode,写一个简短的linker控制在0x1000字节以内,将linker直接填在PE头处,调用时直接call头部的linker实现dll/exe的self link并执行。需求已经测试通过,完整项目不能发出来,但是可以跟大家分享验证阶段的测试代码。

主要原理:
SDK_GetProcAddress 解析kernel32拿到LoadLibraryA和GetProcAddress供linker使用。如果不是裸的代码,这里不需要。
SDK_LoadLibrary 解析dos头和nt头,并将section展开到内存。
RelocImage  进行image base重定向
LinkDLL  加载和连接依赖的dll

这里并没有处理TLS和32位的支持。这个有机会再说吧。

以下代码用mingw-w64编译,可加载运行vs和mingw-w64编译出来的pe。



  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <string.h>

  4. #include "winapi.h"

  5. #ifndef MIN
  6. #define MIN(a, b) ((a) > (b) ? (b) : (a))
  7. #endif

  8. #define RVA(a) ((PVOID)((ULONG_PTR)hExecutable + (a)))
  9. #define K32RVA(a) ((PVOID)((ULONG_PTR)hKernel32 + (a)))

  10. #define API pContext->

  11. typedef struct {
  12.     union {
  13. #ifdef _WIN64
  14.         struct {
  15.             DWORD64  Unused1:63;
  16.             DWORD64  OrdinalIfSet:1;
  17.         } Flag;
  18.         DWORD64 Long;
  19. #else
  20.         struct {
  21.             DWORD  Unused1:31;
  22.             DWORD  OrdinalIfSet:1;
  23.         } Flag;
  24.         DWORD Long;
  25. #endif
  26.         WORD OrdinalNumber;
  27.         DWORD NameAddress;
  28.     } u;
  29. } IMPORT_LOOKUP_DESC, *PIMPORT_LOOKUP_DESC;

  30. typedef struct {
  31.     LoadLibraryA_t LoadLibraryA;
  32.     GetProcAddress_t GetProcAddress;
  33.     GetModuleHandleA_t GetModuleHandleA;
  34. } LINK_CONTEXT, *PLINK_CONTEXT;

  35. typedef struct {
  36.     DWORD Page;
  37.     DWORD BlockSize;
  38.     struct {
  39.         WORD Offset:12;
  40.         WORD Type:4;
  41.     } TypeOffset[0];
  42. } BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;

  43. HMODULE hExecutable = NULL;

  44. int SDK_strcmp(const char *s1, const char *s2)
  45. {
  46.     while(*s1 && *s2) {
  47.         if (*s1 != *s2)
  48.             return -1;
  49.         s1 ++;
  50.         s2 ++;
  51.     }
  52.     return *s2 - *s1;
  53. }

  54. PVOID SDK_GetProcAddress(HMODULE hKernel32, const char *FuncName)
  55. {
  56.     PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hKernel32;
  57.     PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)pDos + pDos->e_lfanew);

  58.     PIMAGE_EXPORT_DIRECTORY EDT = (PIMAGE_EXPORT_DIRECTORY)K32RVA(pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

  59.     // printf("DLL Name: %s\n", K32RVA(EDT->Name));
  60.     // printf("Number Of Functions: %d\n", EDT->NumberOfFunctions);
  61.     // printf("Number Of Names: %d\n", EDT->NumberOfNames);

  62.     PDWORD ExportAddressTable = (PDWORD)MOD_RVA(EDT->AddressOfFunctions);
  63.     PDWORD ExportNamePointerTable = (PDWORD)MOD_RVA(EDT->AddressOfNames);
  64.     PWORD ExportOrdinalTable  = (PWORD)MOD_RVA(EDT->AddressOfNameOrdinals);

  65.     for(size_t i = 0; i < EDT->NumberOfNames; i++)
  66.     {
  67.         PCHAR name = (PCHAR)MOD_RVA(ExportNamePointerTable[i]);

  68.         if (SDK_strcmp(name, FuncName) == 0) {
  69.             WORD Ordinal = ExportOrdinalTable[i];
  70.             return (PVOID)MOD_RVA(ExportAddressTable[Ordinal]);
  71.         }
  72.     }

  73.     return NULL;
  74. }

  75. void LinkDLL(PLINK_CONTEXT pContext, PIMAGE_IMPORT_DESCRIPTOR IDT)
  76. {
  77.     const char* DLLName = (const char*)RVA(IDT->Name);
  78.     HMODULE hDLL = API GetModuleHandleA(DLLName);

  79.     if (!hDLL) {
  80.         hDLL = API LoadLibraryA(DLLName);
  81.     }

  82.     if (!hDLL) {
  83.         return -1;
  84.     }

  85.     printf("** %s **\n", DLLName);

  86.     PIMPORT_LOOKUP_DESC ILD = (PIMPORT_LOOKUP_DESC)RVA(IDT->OriginalFirstThunk);
  87.     PULONG_PTR IAT = (PULONG_PTR)RVA(IDT->FirstThunk);

  88.     while (ILD->u.Long) {
  89.         if (!ILD->u.Flag.OrdinalIfSet) {
  90.             *IAT = (ULONG_PTR) API GetProcAddress(hDLL, (PCSTR)RVA(ILD->u.NameAddress+2));
  91.             printf("%s %p\n", RVA(ILD->u.NameAddress+2), *IAT);
  92.         } else {
  93.             *IAT = (ULONG_PTR) API GetProcAddress(hDLL, (PCSTR)MAKEINTRESOURCE(ILD->u.OrdinalNumber));
  94.             printf("%d %p\n", RVA(ILD->u.OrdinalNumber), *IAT);
  95.         }
  96.         IAT ++;
  97.         ILD ++;
  98.     }
  99. }

  100. void RelocImage(PBASE_RELOCATION_BLOCK BRB, ptrdiff_t Difference)
  101. {
  102.     printf("Difference: %ld\n", Difference);
  103.     for(size_t i = 0; i < (BRB->BlockSize - 8)/2; i++)
  104.     {
  105.         WORD Offset = BRB->TypeOffset[i].Offset;
  106.         printf("0x%.4x\t%d ", Offset, BRB->TypeOffset[i].Type);

  107.         switch(BRB->TypeOffset[i].Type) {
  108.             case IMAGE_REL_BASED_ABSOLUTE:break; // The base relocation is skipped
  109.             case IMAGE_REL_BASED_HIGHLOW: // TODO Not test yet
  110.                 *(DWORD*)RVA(BRB->Page + Offset) += Difference;
  111.                 break;
  112.             case IMAGE_REL_BASED_DIR64:
  113.                 printf("DIR64 %lx => ", *(ptrdiff_t*)RVA(BRB->Page + Offset));
  114.                 *(ptrdiff_t*)RVA(BRB->Page + Offset) += Difference;
  115.                 printf("%lx", *(ptrdiff_t*)RVA(BRB->Page + Offset));
  116.                 break;
  117.             default:
  118.                 fprintf(stderr, "Not support this relocation type yet.");
  119.                 abort();
  120.                 break;
  121.         }
  122.         putchar('\n');
  123.     }
  124. }

  125. #define LLRVA(a) ((PVOID)((char*)Image + (a)))

  126. HMODULE SDK_LoadLibrary(PCSTR LibraryName)
  127. {
  128.     IMAGE_DOS_HEADER DosHdr;
  129.     IMAGE_NT_HEADERS NtHdr;
  130.     HMODULE hModule = NULL;

  131.     FILE *libfp = fopen(LibraryName, "rb");

  132.     if (!libfp)
  133.         goto CLEAN;

  134.     fread(&DosHdr, sizeof(IMAGE_DOS_HEADER), 1, libfp);

  135.     fseek(libfp, DosHdr.e_lfanew, SEEK_SET);
  136.     fread(&NtHdr, sizeof(IMAGE_NT_HEADERS), 1, libfp);

  137.     PVOID Image = VirtualAlloc(NULL, NtHdr.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  138.     if (!Image)
  139.         goto CLEAN;

  140.     fseek(libfp, 0, SEEK_SET);
  141.     fread(Image, NtHdr.OptionalHeader.SizeOfHeaders, 1, libfp);

  142.     PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)Image + DosHdr.e_lfanew);

  143.     PIMAGE_SECTION_HEADER Sections = IMAGE_FIRST_SECTION(pNt);

  144.     for(size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++)
  145.     {
  146.         fseek(libfp, Sections[i].PointerToRawData, SEEK_SET);
  147.         fread(LLRVA(Sections[i].VirtualAddress), Sections[i].SizeOfRawData, 1, libfp);
  148.         printf("%s\n", Sections[i].Name);
  149.     }

  150.     hModule = (HMODULE)Image;
  151. CLEAN:
  152.     if (libfp)
  153.         fclose(libfp);
  154.     return hModule;
  155. }

  156. void SDK_FreeLibrary(HMODULE hModule)
  157. {
  158.     VirtualFree(hModule, 0, MEM_RELEASE);
  159. }

  160. int main(int argc, const char *argv[])
  161. {
  162.     LINK_CONTEXT Context;

  163.     if (argc != 2) {
  164.         fprintf(stderr, "Missing dll\n");
  165.         return -1;
  166.     }

  167.     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
  168.      
  169.     Context.LoadLibraryA = (LoadLibraryA_t)SDK_GetProcAddress(hKernel32, "LoadLibraryA");
  170.     Context.GetProcAddress = (GetProcAddress_t)SDK_GetProcAddress(hKernel32, "GetProcAddress");
  171.     Context.GetModuleHandleA = (GetModuleHandleA_t)SDK_GetProcAddress(hKernel32, "GetModuleHandleA");

  172.     printf("LoadLibraryA\t\t%p\n", Context.LoadLibraryA);
  173.     printf("GetProcAddress\t\t%p\n", Context.GetProcAddress);
  174.     printf("GetModuleHandleA\t%p\n", Context.GetModuleHandleA);

  175.     hExecutable = SDK_LoadLibrary(argv[1]);

  176.     if (hExecutable == NULL) {
  177.         fprintf(stderr, "Can not load dll\n");
  178.         exit(-1);
  179.     }

  180.     PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hExecutable;
  181.     PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((char *)pDos + pDos->e_lfanew);

  182.     if ((PVOID)hExecutable != (PVOID)pNt->OptionalHeader.ImageBase)
  183.     {

  184.         printf("Image Base: %p\n", pNt->OptionalHeader.ImageBase);
  185.         printf("Loaded Base: %p\n", hExecutable);

  186.         ptrdiff_t Difference = (ptrdiff_t)hExecutable - (ptrdiff_t)pNt->OptionalHeader.ImageBase;

  187.         PBASE_RELOCATION_BLOCK BRB = (PBASE_RELOCATION_BLOCK)RVA(pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

  188.         while (BRB->BlockSize) {
  189.             RelocImage(BRB, Difference);
  190.             BRB = (PBASE_RELOCATION_BLOCK)((char*)BRB + BRB->BlockSize);
  191.         }
  192.     }

  193.     PIMAGE_IMPORT_DESCRIPTOR IDT = (PIMAGE_IMPORT_DESCRIPTOR)RVA(pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  194.     while (IDT->Name != 0) {
  195.         LinkDLL(&Context, IDT);
  196.         IDT ++;
  197.     }

  198.     ((void(*)(HMODULE,DWORD,PVOID))RVA(pNt->OptionalHeader.AddressOfEntryPoint))(hExecutable, DLL_PROCESS_ATTACH, NULL);

  199.     SDK_FreeLibrary(hExecutable);

  200.     return 0;
  201. }
复制代码
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-29 22:39

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

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