├── load_file.c ├── load_file.h ├── makefile ├── makefile.common ├── makefile.windows ├── modl_ldr.c ├── modl_ldr.h ├── test.c └── test.exe /load_file.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/360trev/PELoadFromRam/06fa137766eaf2f9ed3f790be76d13ec58141970/load_file.c -------------------------------------------------------------------------------- /load_file.h: -------------------------------------------------------------------------------- 1 | /* Simple read file into memory 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 20 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | */ 23 | #ifndef _LOAD_FILE_H_ 24 | #define _LOAD_FILE_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | uint8_t *load_file(const char *filename, size_t *filelen); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Simple top level make file 3 | # 4 | 5 | ECHO =@echo 6 | MAKE =@make 7 | 8 | default: 9 | $(ECHO) "make " 10 | $(ECHO) "No Specified. Should be one of:" 11 | $(ECHO) "-------------------------------------------------" 12 | $(ECHO) "win32 : Compile for Win32" 13 | $(ECHO) "linux : Compile for Linux" 14 | 15 | clean: 16 | $(MAKE) -s -f makefile.windows clean 17 | $(MAKE) -s -f makefile.linux clean 18 | 19 | win32: 20 | $(MAKE) -s -f makefile.windows 21 | $(ECHO) Done. 22 | linux: 23 | $(MAKE) -s -f makefile.linux 24 | $(ECHO) Done. 25 | -------------------------------------------------------------------------------- /makefile.common: -------------------------------------------------------------------------------- 1 | 2 | OBJ =$(SRC:.c=.o) # replaces the .c from SRC with .o 3 | 4 | %.o: %.c # combined w/ next line will compile recently changed .c files 5 | $(ECHO) Compiling $(notdir $<) ... 6 | $(DEBUG)$(CC) $(CFLAGS) -o $@ -c $< 7 | 8 | .PHONY : all # .PHONY ignores files named all 9 | all: $(EXE) # all is dependent on $(EXE) to be complete 10 | 11 | $(EXE): $(OBJ) # $(EXE) is dependent on all of the files in $(OBJ) to exist 12 | $(ECHO) Linking $(EXE) ... 13 | $(DEBUG)$(CC) $(OBJ) $(LDFLAGS) $(LIBS) -o $@ 14 | $(ECHO) Done 15 | 16 | .PHONY : clean # .PHONY ignores files named clean 17 | clean: 18 | $(ECHO) Deleting *.o $(EXE) ... 19 | $(DEBUG)-$(RM) *.o $(EXE) 20 | -------------------------------------------------------------------------------- /makefile.windows: -------------------------------------------------------------------------------- 1 | # makefile for client 2 | 3 | DEBUG =@ 4 | RM =del 5 | CC =gcc 6 | ECHO =@echo 7 | MAKE =make 8 | CFLAGS =-O2 -D_WIN32_ 9 | LDFLAGS = 10 | 11 | EXE =test.exe 12 | SRC =$(notdir $(foreach dir, ., $(wildcard $(dir)/*.c))) 13 | LIBS = 14 | 15 | include makefile.common 16 | -------------------------------------------------------------------------------- /modl_ldr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.3 4 | * 5 | * Copyright (c) 2004-2012 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 2.0 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.c 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2012 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | * Further updates by 360trev 26 | * 27 | */ 28 | 29 | #ifdef _WIN64 30 | #define POINTER_TYPE ULONGLONG 31 | #else 32 | #define POINTER_TYPE DWORD 33 | #endif 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #ifndef IMAGE_SIZEOF_BASE_RELOCATION 40 | // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!? 41 | #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) 42 | #endif 43 | 44 | #include "modl_ldr.h" 45 | 46 | typedef struct { 47 | PIMAGE_NT_HEADERS headers; 48 | unsigned char *codeBase; 49 | HMODULE *modules; 50 | int numModules; 51 | int initialized; 52 | } MEMORYMODULE, *PMEMORYMODULE; 53 | 54 | typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); 55 | #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] 56 | 57 | static void CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) 58 | { 59 | int i, size; 60 | unsigned char *codeBase = module->codeBase; 61 | unsigned char *dest; 62 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 63 | for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) 64 | { 65 | if (section->SizeOfRawData == 0) { 66 | // section doesn't contain data in the dll itself, but may define uninitialized data 67 | size = old_headers->OptionalHeader.SectionAlignment; 68 | if (size > 0) { 69 | dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, size, MEM_COMMIT, PAGE_READWRITE); 70 | section->Misc.PhysicalAddress = (POINTER_TYPE)dest; 71 | memset(dest, 0, size); 72 | } 73 | // section is empty 74 | continue; 75 | } 76 | // commit memory block and copy data from dll 77 | dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); 78 | memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); 79 | section->Misc.PhysicalAddress = (POINTER_TYPE)dest; 80 | } 81 | } 82 | 83 | // Protection flags for memory pages (Executable, Readable, Writeable) 84 | static int ProtectionFlags[2][2][2] = { 85 | { // not executable 86 | {PAGE_NOACCESS, PAGE_WRITECOPY}, 87 | {PAGE_READONLY, PAGE_READWRITE}, 88 | }, {// executable 89 | {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, 90 | {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, 91 | }, 92 | }; 93 | 94 | static void FinalizeSections(PMEMORYMODULE module) 95 | { 96 | int i; 97 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 98 | #ifdef _WIN64 99 | POINTER_TYPE imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); 100 | #else 101 | #define imageOffset 0 102 | #endif 103 | 104 | // loop through all sections and change access flags 105 | for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { 106 | DWORD protect, oldProtect, size; 107 | int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; 108 | int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; 109 | int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; 110 | 111 | if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { 112 | // section is not needed any more and can safely be freed 113 | VirtualFree((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), section->SizeOfRawData, MEM_DECOMMIT); 114 | continue; 115 | } 116 | // determine protection flags based on characteristics 117 | protect = ProtectionFlags[executable][readable][writeable]; 118 | if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { 119 | protect |= PAGE_NOCACHE; 120 | } 121 | // determine size of region 122 | size = section->SizeOfRawData; 123 | if (size == 0) { 124 | if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { 125 | size = module->headers->OptionalHeader.SizeOfInitializedData; 126 | } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { 127 | size = module->headers->OptionalHeader.SizeOfUninitializedData; 128 | } 129 | } 130 | if (size > 0) { 131 | // change memory access flags 132 | if (VirtualProtect((LPVOID)((POINTER_TYPE)section->Misc.PhysicalAddress | imageOffset), size, protect, &oldProtect) == 0) 133 | printf("Error protecting memory page"); 134 | } 135 | } 136 | #ifndef _WIN64 137 | #undef imageOffset 138 | #endif 139 | } 140 | 141 | static void PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) 142 | { 143 | DWORD i; 144 | unsigned char *codeBase = module->codeBase; 145 | 146 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); 147 | if (directory->Size > 0) { 148 | PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); 149 | for (; relocation->VirtualAddress > 0; ) { 150 | unsigned char *dest = codeBase + relocation->VirtualAddress; 151 | unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); 152 | for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { 153 | DWORD *patchAddrHL; 154 | #ifdef _WIN64 155 | ULONGLONG *patchAddr64; 156 | #endif 157 | int type, offset; 158 | type = *relInfo >> 12; // the upper 4 bits define the type of relocation 159 | offset = *relInfo & 0xfff; // the lower 12 bits define the offset 160 | switch (type) 161 | { 162 | case IMAGE_REL_BASED_ABSOLUTE: break; // skip relocation 163 | case IMAGE_REL_BASED_HIGHLOW: 164 | patchAddrHL = (DWORD *) (dest + offset); // change complete 32 bit address 165 | *patchAddrHL += delta; 166 | break; 167 | #ifdef _WIN64 168 | case IMAGE_REL_BASED_DIR64: 169 | patchAddr64 = (ULONGLONG *) (dest + offset); 170 | *patchAddr64 += delta; 171 | break; 172 | #endif 173 | default: 174 | printf("Unknown relocation: %d\n", type); 175 | break; 176 | } 177 | } 178 | // advance to next relocation block 179 | relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); 180 | } 181 | } 182 | } 183 | 184 | static int BuildImportTable(PMEMORYMODULE module) 185 | { 186 | int result=1; 187 | unsigned char *codeBase = module->codeBase; 188 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); 189 | if (directory->Size > 0) { 190 | PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); 191 | for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { 192 | POINTER_TYPE *thunkRef; 193 | FARPROC *funcRef; 194 | HMODULE handle = LoadLibrary((LPCSTR) (codeBase + importDesc->Name)); 195 | if (handle == NULL) { 196 | printf("Can't load library"); 197 | result = 0; 198 | break; 199 | } 200 | module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); 201 | if (module->modules == NULL) { 202 | result = 0; 203 | break; 204 | } 205 | module->modules[module->numModules++] = handle; 206 | if (importDesc->OriginalFirstThunk) { 207 | thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk); 208 | funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); 209 | } else { 210 | // no hint table 211 | thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk); 212 | funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); 213 | } 214 | for (; *thunkRef; thunkRef++, funcRef++) { 215 | if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { 216 | *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); 217 | } else { 218 | PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef)); 219 | *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name); 220 | } 221 | if (*funcRef == 0) { 222 | result = 0; 223 | break; 224 | } 225 | } 226 | if (!result) { 227 | break; 228 | } 229 | } 230 | } 231 | return result; 232 | } 233 | 234 | HMEMORYMODULE MemoryLoadLibrary(const void *data) 235 | { 236 | PMEMORYMODULE result; 237 | PIMAGE_DOS_HEADER dos_header; 238 | PIMAGE_NT_HEADERS old_header; 239 | unsigned char *code, *headers; 240 | SIZE_T locationDelta; 241 | DllEntryProc DllEntry; 242 | BOOL successfull; 243 | 244 | dos_header = (PIMAGE_DOS_HEADER)data; 245 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { 246 | OutputDebugString("Not a valid executable file.\n"); 247 | return NULL; 248 | } 249 | 250 | old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; 251 | if (old_header->Signature != IMAGE_NT_SIGNATURE) { 252 | printf("No PE header found.\n"); 253 | return NULL; 254 | } 255 | printf("PE header found.\n"); 256 | 257 | printf("PE Image Base size = %ld.\n",old_header->OptionalHeader.SizeOfImage); 258 | // reserve memory for image of library 259 | code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), 260 | old_header->OptionalHeader.SizeOfImage, 261 | MEM_RESERVE, 262 | PAGE_READWRITE); 263 | if (code == NULL) { 264 | // try to allocate memory at arbitrary position 265 | code = (unsigned char *)VirtualAlloc(NULL, 266 | old_header->OptionalHeader.SizeOfImage, 267 | MEM_RESERVE, 268 | PAGE_READWRITE); 269 | if (code == NULL) { 270 | printf("Can't reserve memory"); 271 | return NULL; 272 | } 273 | } 274 | 275 | result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); 276 | result->codeBase = code; 277 | result->numModules = 0; 278 | result->modules = NULL; 279 | result->initialized = 0; 280 | 281 | // XXX: is it correct to commit the complete memory region at once? 282 | // calling DllEntry raises an exception if we don't... 283 | VirtualAlloc(code, 284 | old_header->OptionalHeader.SizeOfImage, 285 | MEM_COMMIT, 286 | PAGE_READWRITE); 287 | 288 | // commit memory for headers 289 | headers = (unsigned char *)VirtualAlloc(code, 290 | old_header->OptionalHeader.SizeOfHeaders, 291 | MEM_COMMIT, 292 | PAGE_READWRITE); 293 | 294 | // copy PE header to code 295 | memcpy(headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); 296 | result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; 297 | 298 | // update position 299 | result->headers->OptionalHeader.ImageBase = (POINTER_TYPE)code; 300 | 301 | // copy sections from DLL file block to new memory location 302 | CopySections(data, old_header, result); 303 | 304 | // adjust base address of imported data 305 | locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); 306 | if (locationDelta != 0) { 307 | PerformBaseRelocation(result, locationDelta); 308 | } 309 | 310 | // load required dlls and adjust function table of imports 311 | if (!BuildImportTable(result)) { goto error; } 312 | 313 | // mark memory pages depending on section headers and release 314 | // sections that are marked as "discardable" 315 | FinalizeSections(result); 316 | 317 | // get entry point of loaded library 318 | if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) { 319 | DllEntry = (DllEntryProc) (code + result->headers->OptionalHeader.AddressOfEntryPoint); 320 | if (DllEntry == 0) { 321 | printf("Library has no entry point.\n"); 322 | goto error; 323 | } else { 324 | printf("Found library Entry point %p.\n",DllEntry); 325 | } 326 | printf(">>> Executing DLL entry point.\n"); 327 | // notify library about attaching to process 328 | successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); 329 | printf(">>> Left DLL entry point, result %d.\n",successfull); 330 | if (!successfull) { 331 | printf("Can't attach library.\n"); 332 | goto error; 333 | } 334 | result->initialized = 1; 335 | } 336 | return (HMEMORYMODULE)result; 337 | error: 338 | // cleanup 339 | MemoryFreeLibrary(result); 340 | return NULL; 341 | } 342 | 343 | FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) 344 | { 345 | unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; 346 | int idx=-1; 347 | DWORD i, *nameRef; 348 | WORD *ordinal; 349 | PIMAGE_EXPORT_DIRECTORY exports; 350 | PIMAGE_DATA_DIRECTORY directory; 351 | 352 | directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); 353 | if (directory->Size == 0) { printf("DLL has no export table found\n"); return NULL; } 354 | 355 | exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); 356 | if (exports->NumberOfNames == 0) { printf("DLL doesn't export any names\n"); return NULL; } 357 | if (exports->NumberOfFunctions == 0) { printf("DLL doesn't export any functions\n"); return NULL; } 358 | 359 | // search function name in list of exported names 360 | nameRef = (DWORD *) (codeBase + exports->AddressOfNames); 361 | ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); 362 | 363 | for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) 364 | { 365 | if (stricmp(name, (const char *) (codeBase + (*nameRef))) == 0) 366 | { 367 | idx = *ordinal; 368 | break; 369 | } 370 | } 371 | 372 | if (idx == -1) { 373 | // exported symbol not found 374 | return NULL; 375 | } 376 | 377 | if ((DWORD)idx > exports->NumberOfFunctions) { 378 | // name <-> ordinal number don't match 379 | return NULL; 380 | } 381 | // AddressOfFunctions contains the RVAs to the "real" functions 382 | return (FARPROC) (codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4)))); 383 | } 384 | 385 | void MemoryFreeLibrary(HMEMORYMODULE mod) 386 | { 387 | int i; 388 | PMEMORYMODULE module = (PMEMORYMODULE)mod; 389 | if (module != NULL) 390 | { 391 | if (module->initialized != 0) { 392 | // notify library about detaching from process 393 | DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); 394 | (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); 395 | module->initialized = 0; 396 | } 397 | if (module->modules != NULL) { 398 | // free previously opened libraries 399 | for (i=0; inumModules; i++) { 400 | if (module->modules[i] != INVALID_HANDLE_VALUE) { 401 | FreeLibrary(module->modules[i]); 402 | } 403 | } 404 | free(module->modules); 405 | } 406 | if (module->codeBase != NULL) { VirtualFree(module->codeBase, 0, MEM_RELEASE);} // release memory of library 407 | HeapFree(GetProcessHeap(), 0, module); 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /modl_ldr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.3 4 | * 5 | * Copyright (c) 2004-2012 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 2.0 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.h 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2012 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | */ 26 | 27 | #ifndef __MEMORY_MODULE_HEADER 28 | #define __MEMORY_MODULE_HEADER 29 | 30 | #include 31 | 32 | typedef void *HMEMORYMODULE; 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | HMEMORYMODULE MemoryLoadLibrary(const void *); 39 | 40 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); 41 | 42 | void MemoryFreeLibrary(HMEMORYMODULE); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif // __MEMORY_MODULE_HEADER 49 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* Example of loading a DLL from alternative source (with in ram relocation!) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 20 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | IN THE SOFTWARE. 22 | */ 23 | 24 | #define WIN32_LEAN_AND_MEAN 25 | #include 26 | #include 27 | #include 28 | #include "modl_ldr.h" 29 | #include "load_file.h" 30 | 31 | // prototype of the method exported from our dll 32 | typedef int (*addNumberProc)(int, int); 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | unsigned char *data; 37 | size_t filelen; 38 | HMEMORYMODULE testBase; // dll base handle 39 | addNumberProc addNumber; // function ptr 40 | 41 | if(argc < 3){ 42 | printf("Usage: %s \n",argv[0]); 43 | return -1; 44 | } 45 | 46 | /* load the dll file into memory 47 | * 48 | * Note:(This step could have been from an encrypted, compressed or signed file or 49 | * even dynamically downloaded from the web (!), etc.). 50 | */ 51 | data = load_file(argv[1], &filelen); 52 | if(data == 0) { printf("failed to load %d, exiting.\n",argv[1]); return 0; } 53 | 54 | printf("Opening lib ..\n"); 55 | /* load shared library from buffer, relocate it, etc. */ 56 | if((testBase = MemoryLoadLibrary(data)) == NULL) { 57 | printf("Can't load library.\n"); 58 | free(data); 59 | return -1; 60 | } 61 | 62 | printf("Finding api call ..\n"); 63 | /* now we can lookup any named vtable function(s) we want.. */ 64 | addNumber = (addNumberProc)MemoryGetProcAddress(testBase, argv[2]); 65 | if(addNumber != 0) { 66 | printf("Got it! %d = %s(1,2);\n", addNumber(1, 2),argv[2]); /* example use of dll exported function */ 67 | } else { 68 | printf("Sorry %s() api not found in this dll.\n",argv[2]); 69 | } 70 | 71 | printf("Closing lib ..\n"); 72 | /* close the library */ 73 | MemoryFreeLibrary(testBase); 74 | 75 | /* free loaded dll buffer memory */ 76 | free(data); 77 | 78 | return 0; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/360trev/PELoadFromRam/06fa137766eaf2f9ed3f790be76d13ec58141970/test.exe --------------------------------------------------------------------------------