MemoryModule.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /*
  2. * Memory DLL loading code
  3. * Version 0.0.4
  4. *
  5. * Copyright (c) 2004-2015 by Joachim Bauch / [email protected]
  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-2015
  23. * Joachim Bauch. All Rights Reserved.
  24. *
  25. *
  26. * THeller: Added binary search in MemoryGetProcAddress function
  27. * (#define USE_BINARY_SEARCH to enable it). This gives a very large
  28. * speedup for libraries that exports lots of functions.
  29. *
  30. * These portions are Copyright (C) 2013 Thomas Heller.
  31. */
  32. #include <windows.h>
  33. #include <winnt.h>
  34. #include <stddef.h>
  35. #include <tchar.h>
  36. #ifdef DEBUG_OUTPUT
  37. #include <stdio.h>
  38. #endif
  39. #if _MSC_VER
  40. // Disable warning about data -> function pointer conversion
  41. #pragma warning(disable:4055)
  42. // C4244: conversion from 'uintptr_t' to 'DWORD', possible loss of data.
  43. #pragma warning(error: 4244)
  44. // C4267: conversion from 'size_t' to 'int', possible loss of data.
  45. #pragma warning(error: 4267)
  46. #define inline __inline
  47. #endif
  48. #ifndef IMAGE_SIZEOF_BASE_RELOCATION
  49. // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
  50. #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
  51. #endif
  52. #ifdef _WIN64
  53. #define HOST_MACHINE IMAGE_FILE_MACHINE_AMD64
  54. #else
  55. #define HOST_MACHINE IMAGE_FILE_MACHINE_I386
  56. #endif
  57. #include "MemoryModule.h"
  58. struct ExportNameEntry {
  59. LPCSTR name;
  60. WORD idx;
  61. };
  62. typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
  63. typedef int (WINAPI *ExeEntryProc)(void);
  64. #ifdef _WIN64
  65. typedef struct POINTER_LIST {
  66. struct POINTER_LIST *next;
  67. void *address;
  68. } POINTER_LIST;
  69. #endif
  70. typedef struct {
  71. PIMAGE_NT_HEADERS headers;
  72. unsigned char *codeBase;
  73. HCUSTOMMODULE *modules;
  74. int numModules;
  75. BOOL initialized;
  76. BOOL isDLL;
  77. BOOL isRelocated;
  78. CustomAllocFunc alloc;
  79. CustomFreeFunc free;
  80. CustomLoadLibraryFunc loadLibrary;
  81. CustomGetProcAddressFunc getProcAddress;
  82. CustomFreeLibraryFunc freeLibrary;
  83. struct ExportNameEntry *nameExportsTable;
  84. void *userdata;
  85. ExeEntryProc exeEntry;
  86. DWORD pageSize;
  87. #ifdef _WIN64
  88. POINTER_LIST *blockedMemory;
  89. #endif
  90. } MEMORYMODULE, *PMEMORYMODULE;
  91. typedef struct {
  92. LPVOID address;
  93. LPVOID alignedAddress;
  94. SIZE_T size;
  95. DWORD characteristics;
  96. BOOL last;
  97. } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA;
  98. #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
  99. static inline uintptr_t
  100. AlignValueDown(uintptr_t value, uintptr_t alignment) {
  101. return value & ~(alignment - 1);
  102. }
  103. static inline LPVOID
  104. AlignAddressDown(LPVOID address, uintptr_t alignment) {
  105. return (LPVOID) AlignValueDown((uintptr_t) address, alignment);
  106. }
  107. static inline size_t
  108. AlignValueUp(size_t value, size_t alignment) {
  109. return (value + alignment - 1) & ~(alignment - 1);
  110. }
  111. static inline void*
  112. OffsetPointer(void* data, ptrdiff_t offset) {
  113. return (void*) ((uintptr_t) data + offset);
  114. }
  115. static inline void
  116. OutputLastError(const char *msg)
  117. {
  118. #ifndef DEBUG_OUTPUT
  119. UNREFERENCED_PARAMETER(msg);
  120. #else
  121. LPVOID tmp;
  122. char *tmpmsg;
  123. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  124. NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL);
  125. tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3);
  126. sprintf(tmpmsg, "%s: %s", msg, tmp);
  127. OutputDebugString(tmpmsg);
  128. LocalFree(tmpmsg);
  129. LocalFree(tmp);
  130. #endif
  131. }
  132. #ifdef _WIN64
  133. static void
  134. FreePointerList(POINTER_LIST *head, CustomFreeFunc freeMemory, void *userdata)
  135. {
  136. POINTER_LIST *node = head;
  137. while (node) {
  138. POINTER_LIST *next;
  139. freeMemory(node->address, 0, MEM_RELEASE, userdata);
  140. next = node->next;
  141. free(node);
  142. node = next;
  143. }
  144. }
  145. #endif
  146. static BOOL
  147. CheckSize(size_t size, size_t expected) {
  148. if (size < expected) {
  149. SetLastError(ERROR_INVALID_DATA);
  150. return FALSE;
  151. }
  152. return TRUE;
  153. }
  154. static BOOL
  155. CopySections(const unsigned char *data, size_t size, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
  156. {
  157. int i, section_size;
  158. unsigned char *codeBase = module->codeBase;
  159. unsigned char *dest;
  160. PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
  161. for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
  162. if (section->SizeOfRawData == 0) {
  163. // section doesn't contain data in the dll itself, but may define
  164. // uninitialized data
  165. section_size = old_headers->OptionalHeader.SectionAlignment;
  166. if (section_size > 0) {
  167. dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress,
  168. section_size,
  169. MEM_COMMIT,
  170. PAGE_READWRITE,
  171. module->userdata);
  172. if (dest == NULL) {
  173. return FALSE;
  174. }
  175. // Always use position from file to support alignments smaller
  176. // than page size (allocation above will align to page size).
  177. dest = codeBase + section->VirtualAddress;
  178. // NOTE: On 64bit systems we truncate to 32bit here but expand
  179. // again later when "PhysicalAddress" is used.
  180. section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff);
  181. memset(dest, 0, section_size);
  182. }
  183. // section is empty
  184. continue;
  185. }
  186. if (!CheckSize(size, section->PointerToRawData + section->SizeOfRawData)) {
  187. return FALSE;
  188. }
  189. // commit memory block and copy data from dll
  190. dest = (unsigned char *)module->alloc(codeBase + section->VirtualAddress,
  191. section->SizeOfRawData,
  192. MEM_COMMIT,
  193. PAGE_READWRITE,
  194. module->userdata);
  195. if (dest == NULL) {
  196. return FALSE;
  197. }
  198. // Always use position from file to support alignments smaller
  199. // than page size (allocation above will align to page size).
  200. dest = codeBase + section->VirtualAddress;
  201. memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
  202. // NOTE: On 64bit systems we truncate to 32bit here but expand
  203. // again later when "PhysicalAddress" is used.
  204. section->Misc.PhysicalAddress = (DWORD) ((uintptr_t) dest & 0xffffffff);
  205. }
  206. return TRUE;
  207. }
  208. // Protection flags for memory pages (Executable, Readable, Writeable)
  209. static int ProtectionFlags[2][2][2] = {
  210. {
  211. // not executable
  212. {PAGE_NOACCESS, PAGE_WRITECOPY},
  213. {PAGE_READONLY, PAGE_READWRITE},
  214. }, {
  215. // executable
  216. {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
  217. {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
  218. },
  219. };
  220. static SIZE_T
  221. GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) {
  222. DWORD size = section->SizeOfRawData;
  223. if (size == 0) {
  224. if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
  225. size = module->headers->OptionalHeader.SizeOfInitializedData;
  226. } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
  227. size = module->headers->OptionalHeader.SizeOfUninitializedData;
  228. }
  229. }
  230. return (SIZE_T) size;
  231. }
  232. static BOOL
  233. FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) {
  234. DWORD protect, oldProtect;
  235. BOOL executable;
  236. BOOL readable;
  237. BOOL writeable;
  238. if (sectionData->size == 0) {
  239. return TRUE;
  240. }
  241. if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) {
  242. // section is not needed any more and can safely be freed
  243. if (sectionData->address == sectionData->alignedAddress &&
  244. (sectionData->last ||
  245. module->headers->OptionalHeader.SectionAlignment == module->pageSize ||
  246. (sectionData->size % module->pageSize) == 0)
  247. ) {
  248. // Only allowed to decommit whole pages
  249. module->free(sectionData->address, sectionData->size, MEM_DECOMMIT, module->userdata);
  250. }
  251. return TRUE;
  252. }
  253. // determine protection flags based on characteristics
  254. executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
  255. readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0;
  256. writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0;
  257. protect = ProtectionFlags[executable][readable][writeable];
  258. if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) {
  259. protect |= PAGE_NOCACHE;
  260. }
  261. // change memory access flags
  262. if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) {
  263. OutputLastError("Error protecting memory page");
  264. return FALSE;
  265. }
  266. return TRUE;
  267. }
  268. static BOOL
  269. FinalizeSections(PMEMORYMODULE module)
  270. {
  271. int i;
  272. PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
  273. #ifdef _WIN64
  274. // "PhysicalAddress" might have been truncated to 32bit above, expand to
  275. // 64bits again.
  276. uintptr_t imageOffset = ((uintptr_t) module->headers->OptionalHeader.ImageBase & 0xffffffff00000000);
  277. #else
  278. static const uintptr_t imageOffset = 0;
  279. #endif
  280. SECTIONFINALIZEDATA sectionData;
  281. sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset);
  282. sectionData.alignedAddress = AlignAddressDown(sectionData.address, module->pageSize);
  283. sectionData.size = GetRealSectionSize(module, section);
  284. sectionData.characteristics = section->Characteristics;
  285. sectionData.last = FALSE;
  286. section++;
  287. // loop through all sections and change access flags
  288. for (i=1; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
  289. LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset);
  290. LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize);
  291. SIZE_T sectionSize = GetRealSectionSize(module, section);
  292. // Combine access flags of all sections that share a page
  293. // TODO(fancycode): We currently share flags of a trailing large section
  294. // with the page of a first small section. This should be optimized.
  295. if (sectionData.alignedAddress == alignedAddress || (uintptr_t) sectionData.address + sectionData.size > (uintptr_t) alignedAddress) {
  296. // Section shares page with previous
  297. if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) {
  298. sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE;
  299. } else {
  300. sectionData.characteristics |= section->Characteristics;
  301. }
  302. sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t) sectionSize)) - (uintptr_t) sectionData.address;
  303. continue;
  304. }
  305. if (!FinalizeSection(module, &sectionData)) {
  306. return FALSE;
  307. }
  308. sectionData.address = sectionAddress;
  309. sectionData.alignedAddress = alignedAddress;
  310. sectionData.size = sectionSize;
  311. sectionData.characteristics = section->Characteristics;
  312. }
  313. sectionData.last = TRUE;
  314. if (!FinalizeSection(module, &sectionData)) {
  315. return FALSE;
  316. }
  317. return TRUE;
  318. }
  319. static BOOL
  320. ExecuteTLS(PMEMORYMODULE module)
  321. {
  322. unsigned char *codeBase = module->codeBase;
  323. PIMAGE_TLS_DIRECTORY tls;
  324. PIMAGE_TLS_CALLBACK* callback;
  325. PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_TLS);
  326. if (directory->VirtualAddress == 0) {
  327. return TRUE;
  328. }
  329. tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress);
  330. callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks;
  331. if (callback) {
  332. while (*callback) {
  333. (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL);
  334. callback++;
  335. }
  336. }
  337. return TRUE;
  338. }
  339. static BOOL
  340. PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta)
  341. {
  342. unsigned char *codeBase = module->codeBase;
  343. PIMAGE_BASE_RELOCATION relocation;
  344. PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
  345. if (directory->Size == 0) {
  346. return (delta == 0);
  347. }
  348. relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress);
  349. for (; relocation->VirtualAddress > 0; ) {
  350. DWORD i;
  351. unsigned char *dest = codeBase + relocation->VirtualAddress;
  352. unsigned short *relInfo = (unsigned short*) OffsetPointer(relocation, IMAGE_SIZEOF_BASE_RELOCATION);
  353. for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) {
  354. // the upper 4 bits define the type of relocation
  355. int type = *relInfo >> 12;
  356. // the lower 12 bits define the offset
  357. int offset = *relInfo & 0xfff;
  358. switch (type)
  359. {
  360. case IMAGE_REL_BASED_ABSOLUTE:
  361. // skip relocation
  362. break;
  363. case IMAGE_REL_BASED_HIGHLOW:
  364. // change complete 32 bit address
  365. {
  366. DWORD *patchAddrHL = (DWORD *) (dest + offset);
  367. *patchAddrHL += (DWORD) delta;
  368. }
  369. break;
  370. #ifdef _WIN64
  371. case IMAGE_REL_BASED_DIR64:
  372. {
  373. ULONGLONG *patchAddr64 = (ULONGLONG *) (dest + offset);
  374. *patchAddr64 += (ULONGLONG) delta;
  375. }
  376. break;
  377. #endif
  378. default:
  379. //printf("Unknown relocation: %d\n", type);
  380. break;
  381. }
  382. }
  383. // advance to next relocation block
  384. relocation = (PIMAGE_BASE_RELOCATION) OffsetPointer(relocation, relocation->SizeOfBlock);
  385. }
  386. return TRUE;
  387. }
  388. static BOOL
  389. BuildImportTable(PMEMORYMODULE module)
  390. {
  391. unsigned char *codeBase = module->codeBase;
  392. PIMAGE_IMPORT_DESCRIPTOR importDesc;
  393. BOOL result = TRUE;
  394. PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
  395. if (directory->Size == 0) {
  396. return TRUE;
  397. }
  398. importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);
  399. for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) {
  400. uintptr_t *thunkRef;
  401. FARPROC *funcRef;
  402. HCUSTOMMODULE *tmp;
  403. HCUSTOMMODULE handle = module->loadLibrary((LPCSTR) (codeBase + importDesc->Name), module->userdata);
  404. if (handle == NULL) {
  405. SetLastError(ERROR_MOD_NOT_FOUND);
  406. result = FALSE;
  407. break;
  408. }
  409. tmp = (HCUSTOMMODULE *) realloc(module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE)));
  410. if (tmp == NULL) {
  411. module->freeLibrary(handle, module->userdata);
  412. SetLastError(ERROR_OUTOFMEMORY);
  413. result = FALSE;
  414. break;
  415. }
  416. module->modules = tmp;
  417. module->modules[module->numModules++] = handle;
  418. if (importDesc->OriginalFirstThunk) {
  419. thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk);
  420. funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
  421. } else {
  422. // no hint table
  423. thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk);
  424. funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
  425. }
  426. for (; *thunkRef; thunkRef++, funcRef++) {
  427. if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
  428. *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata);
  429. } else {
  430. PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));
  431. *funcRef = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata);
  432. }
  433. if (*funcRef == 0) {
  434. result = FALSE;
  435. break;
  436. }
  437. }
  438. if (!result) {
  439. module->freeLibrary(handle, module->userdata);
  440. SetLastError(ERROR_PROC_NOT_FOUND);
  441. break;
  442. }
  443. }
  444. return result;
  445. }
  446. LPVOID MemoryDefaultAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect, void* userdata)
  447. {
  448. UNREFERENCED_PARAMETER(userdata);
  449. return VirtualAlloc(address, size, allocationType, protect);
  450. }
  451. BOOL MemoryDefaultFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType, void* userdata)
  452. {
  453. UNREFERENCED_PARAMETER(userdata);
  454. return VirtualFree(lpAddress, dwSize, dwFreeType);
  455. }
  456. HCUSTOMMODULE MemoryDefaultLoadLibrary(LPCSTR filename, void *userdata)
  457. {
  458. HMODULE result;
  459. UNREFERENCED_PARAMETER(userdata);
  460. result = LoadLibraryA(filename);
  461. if (result == NULL) {
  462. return NULL;
  463. }
  464. return (HCUSTOMMODULE) result;
  465. }
  466. FARPROC MemoryDefaultGetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata)
  467. {
  468. UNREFERENCED_PARAMETER(userdata);
  469. return (FARPROC) GetProcAddress((HMODULE) module, name);
  470. }
  471. void MemoryDefaultFreeLibrary(HCUSTOMMODULE module, void *userdata)
  472. {
  473. UNREFERENCED_PARAMETER(userdata);
  474. FreeLibrary((HMODULE) module);
  475. }
  476. HMEMORYMODULE MemoryLoadLibrary(const void *data, size_t size)
  477. {
  478. return MemoryLoadLibraryEx(data, size, MemoryDefaultAlloc, MemoryDefaultFree, MemoryDefaultLoadLibrary, MemoryDefaultGetProcAddress, MemoryDefaultFreeLibrary, NULL);
  479. }
  480. HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
  481. CustomAllocFunc allocMemory,
  482. CustomFreeFunc freeMemory,
  483. CustomLoadLibraryFunc loadLibrary,
  484. CustomGetProcAddressFunc getProcAddress,
  485. CustomFreeLibraryFunc freeLibrary,
  486. void *userdata)
  487. {
  488. PMEMORYMODULE result = NULL;
  489. PIMAGE_DOS_HEADER dos_header;
  490. PIMAGE_NT_HEADERS old_header;
  491. unsigned char *code, *headers;
  492. ptrdiff_t locationDelta;
  493. SYSTEM_INFO sysInfo;
  494. PIMAGE_SECTION_HEADER section;
  495. DWORD i;
  496. size_t optionalSectionSize;
  497. size_t lastSectionEnd = 0;
  498. size_t alignedImageSize;
  499. #ifdef _WIN64
  500. POINTER_LIST *blockedMemory = NULL;
  501. #endif
  502. if (!CheckSize(size, sizeof(IMAGE_DOS_HEADER))) {
  503. return NULL;
  504. }
  505. dos_header = (PIMAGE_DOS_HEADER)data;
  506. if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
  507. SetLastError(ERROR_BAD_EXE_FORMAT);
  508. return NULL;
  509. }
  510. if (!CheckSize(size, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS))) {
  511. return NULL;
  512. }
  513. old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew];
  514. if (old_header->Signature != IMAGE_NT_SIGNATURE) {
  515. SetLastError(ERROR_BAD_EXE_FORMAT);
  516. return NULL;
  517. }
  518. if (old_header->FileHeader.Machine != HOST_MACHINE) {
  519. SetLastError(ERROR_BAD_EXE_FORMAT);
  520. return NULL;
  521. }
  522. if (old_header->OptionalHeader.SectionAlignment & 1) {
  523. // Only support section alignments that are a multiple of 2
  524. SetLastError(ERROR_BAD_EXE_FORMAT);
  525. return NULL;
  526. }
  527. section = IMAGE_FIRST_SECTION(old_header);
  528. optionalSectionSize = old_header->OptionalHeader.SectionAlignment;
  529. for (i=0; i<old_header->FileHeader.NumberOfSections; i++, section++) {
  530. size_t endOfSection;
  531. if (section->SizeOfRawData == 0) {
  532. // Section without data in the DLL
  533. endOfSection = section->VirtualAddress + optionalSectionSize;
  534. } else {
  535. endOfSection = section->VirtualAddress + section->SizeOfRawData;
  536. }
  537. if (endOfSection > lastSectionEnd) {
  538. lastSectionEnd = endOfSection;
  539. }
  540. }
  541. GetNativeSystemInfo(&sysInfo);
  542. alignedImageSize = AlignValueUp(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize);
  543. if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) {
  544. SetLastError(ERROR_BAD_EXE_FORMAT);
  545. return NULL;
  546. }
  547. // reserve memory for image of library
  548. // XXX: is it correct to commit the complete memory region at once?
  549. // calling DllEntry raises an exception if we don't...
  550. code = (unsigned char *)allocMemory((LPVOID)(old_header->OptionalHeader.ImageBase),
  551. alignedImageSize,
  552. MEM_RESERVE | MEM_COMMIT,
  553. PAGE_READWRITE,
  554. userdata);
  555. if (code == NULL) {
  556. // try to allocate memory at arbitrary position
  557. code = (unsigned char *)allocMemory(NULL,
  558. alignedImageSize,
  559. MEM_RESERVE | MEM_COMMIT,
  560. PAGE_READWRITE,
  561. userdata);
  562. if (code == NULL) {
  563. SetLastError(ERROR_OUTOFMEMORY);
  564. return NULL;
  565. }
  566. }
  567. #ifdef _WIN64
  568. // Memory block may not span 4 GB boundaries.
  569. while ((((uintptr_t) code) >> 32) < (((uintptr_t) (code + alignedImageSize)) >> 32)) {
  570. POINTER_LIST *node = (POINTER_LIST*) malloc(sizeof(POINTER_LIST));
  571. if (!node) {
  572. freeMemory(code, 0, MEM_RELEASE, userdata);
  573. FreePointerList(blockedMemory, freeMemory, userdata);
  574. SetLastError(ERROR_OUTOFMEMORY);
  575. return NULL;
  576. }
  577. node->next = blockedMemory;
  578. node->address = code;
  579. blockedMemory = node;
  580. code = (unsigned char *)allocMemory(NULL,
  581. alignedImageSize,
  582. MEM_RESERVE | MEM_COMMIT,
  583. PAGE_READWRITE,
  584. userdata);
  585. if (code == NULL) {
  586. FreePointerList(blockedMemory, freeMemory, userdata);
  587. SetLastError(ERROR_OUTOFMEMORY);
  588. return NULL;
  589. }
  590. }
  591. #endif
  592. result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE));
  593. if (result == NULL) {
  594. freeMemory(code, 0, MEM_RELEASE, userdata);
  595. #ifdef _WIN64
  596. FreePointerList(blockedMemory, freeMemory, userdata);
  597. #endif
  598. SetLastError(ERROR_OUTOFMEMORY);
  599. return NULL;
  600. }
  601. result->codeBase = code;
  602. result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0;
  603. result->alloc = allocMemory;
  604. result->free = freeMemory;
  605. result->loadLibrary = loadLibrary;
  606. result->getProcAddress = getProcAddress;
  607. result->freeLibrary = freeLibrary;
  608. result->userdata = userdata;
  609. result->pageSize = sysInfo.dwPageSize;
  610. #ifdef _WIN64
  611. result->blockedMemory = blockedMemory;
  612. #endif
  613. if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) {
  614. goto error;
  615. }
  616. // commit memory for headers
  617. headers = (unsigned char *)allocMemory(code,
  618. old_header->OptionalHeader.SizeOfHeaders,
  619. MEM_COMMIT,
  620. PAGE_READWRITE,
  621. userdata);
  622. // copy PE header to code
  623. memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders);
  624. result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew];
  625. // update position
  626. result->headers->OptionalHeader.ImageBase = (uintptr_t)code;
  627. // copy sections from DLL file block to new memory location
  628. if (!CopySections((const unsigned char *) data, size, old_header, result)) {
  629. goto error;
  630. }
  631. // adjust base address of imported data
  632. locationDelta = (ptrdiff_t)(result->headers->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase);
  633. if (locationDelta != 0) {
  634. result->isRelocated = PerformBaseRelocation(result, locationDelta);
  635. } else {
  636. result->isRelocated = TRUE;
  637. }
  638. // load required dlls and adjust function table of imports
  639. if (!BuildImportTable(result)) {
  640. goto error;
  641. }
  642. // mark memory pages depending on section headers and release
  643. // sections that are marked as "discardable"
  644. if (!FinalizeSections(result)) {
  645. goto error;
  646. }
  647. // TLS callbacks are executed BEFORE the main loading
  648. if (!ExecuteTLS(result)) {
  649. goto error;
  650. }
  651. // get entry point of loaded library
  652. if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) {
  653. if (result->isDLL) {
  654. DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint);
  655. // notify library about attaching to process
  656. BOOL successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0);
  657. if (!successfull) {
  658. SetLastError(ERROR_DLL_INIT_FAILED);
  659. goto error;
  660. }
  661. result->initialized = TRUE;
  662. } else {
  663. result->exeEntry = (ExeEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint);
  664. }
  665. } else {
  666. result->exeEntry = NULL;
  667. }
  668. return (HMEMORYMODULE)result;
  669. error:
  670. // cleanup
  671. MemoryFreeLibrary(result);
  672. return NULL;
  673. }
  674. static int _compare(const void *a, const void *b)
  675. {
  676. const struct ExportNameEntry *p1 = (const struct ExportNameEntry*) a;
  677. const struct ExportNameEntry *p2 = (const struct ExportNameEntry*) b;
  678. return strcmp(p1->name, p2->name);
  679. }
  680. static int _find(const void *a, const void *b)
  681. {
  682. LPCSTR *name = (LPCSTR *) a;
  683. const struct ExportNameEntry *p = (const struct ExportNameEntry*) b;
  684. return strcmp(*name, p->name);
  685. }
  686. FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name)
  687. {
  688. PMEMORYMODULE module = (PMEMORYMODULE)mod;
  689. unsigned char *codeBase = module->codeBase;
  690. DWORD idx = 0;
  691. PIMAGE_EXPORT_DIRECTORY exports;
  692. PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
  693. if (directory->Size == 0) {
  694. // no export table found
  695. SetLastError(ERROR_PROC_NOT_FOUND);
  696. return NULL;
  697. }
  698. exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress);
  699. if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) {
  700. // DLL doesn't export anything
  701. SetLastError(ERROR_PROC_NOT_FOUND);
  702. return NULL;
  703. }
  704. if (HIWORD(name) == 0) {
  705. // load function by ordinal value
  706. if (LOWORD(name) < exports->Base) {
  707. SetLastError(ERROR_PROC_NOT_FOUND);
  708. return NULL;
  709. }
  710. idx = LOWORD(name) - exports->Base;
  711. } else if (!exports->NumberOfNames) {
  712. SetLastError(ERROR_PROC_NOT_FOUND);
  713. return NULL;
  714. } else {
  715. const struct ExportNameEntry *found;
  716. // Lazily build name table and sort it by names
  717. if (!module->nameExportsTable) {
  718. DWORD i;
  719. DWORD *nameRef = (DWORD *) (codeBase + exports->AddressOfNames);
  720. WORD *ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals);
  721. struct ExportNameEntry *entry = (struct ExportNameEntry*) malloc(exports->NumberOfNames * sizeof(struct ExportNameEntry));
  722. module->nameExportsTable = entry;
  723. if (!entry) {
  724. SetLastError(ERROR_OUTOFMEMORY);
  725. return NULL;
  726. }
  727. for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++, entry++) {
  728. entry->name = (const char *) (codeBase + (*nameRef));
  729. entry->idx = *ordinal;
  730. }
  731. qsort(module->nameExportsTable,
  732. exports->NumberOfNames,
  733. sizeof(struct ExportNameEntry), _compare);
  734. }
  735. // search function name in list of exported names with binary search
  736. found = (const struct ExportNameEntry*) bsearch(&name,
  737. module->nameExportsTable,
  738. exports->NumberOfNames,
  739. sizeof(struct ExportNameEntry), _find);
  740. if (!found) {
  741. // exported symbol not found
  742. SetLastError(ERROR_PROC_NOT_FOUND);
  743. return NULL;
  744. }
  745. idx = found->idx;
  746. }
  747. if (idx > exports->NumberOfFunctions) {
  748. // name <-> ordinal number don't match
  749. SetLastError(ERROR_PROC_NOT_FOUND);
  750. return NULL;
  751. }
  752. // AddressOfFunctions contains the RVAs to the "real" functions
  753. return (FARPROC)(LPVOID)(codeBase + (*(DWORD *) (codeBase + exports->AddressOfFunctions + (idx*4))));
  754. }
  755. void MemoryFreeLibrary(HMEMORYMODULE mod)
  756. {
  757. PMEMORYMODULE module = (PMEMORYMODULE)mod;
  758. if (module == NULL) {
  759. return;
  760. }
  761. if (module->initialized) {
  762. // notify library about detaching from process
  763. DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint);
  764. (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0);
  765. }
  766. free(module->nameExportsTable);
  767. if (module->modules != NULL) {
  768. // free previously opened libraries
  769. int i;
  770. for (i=0; i<module->numModules; i++) {
  771. if (module->modules[i] != NULL) {
  772. module->freeLibrary(module->modules[i], module->userdata);
  773. }
  774. }
  775. free(module->modules);
  776. }
  777. if (module->codeBase != NULL) {
  778. // release memory of library
  779. module->free(module->codeBase, 0, MEM_RELEASE, module->userdata);
  780. }
  781. #ifdef _WIN64
  782. FreePointerList(module->blockedMemory, module->free, module->userdata);
  783. #endif
  784. HeapFree(GetProcessHeap(), 0, module);
  785. }
  786. int MemoryCallEntryPoint(HMEMORYMODULE mod)
  787. {
  788. PMEMORYMODULE module = (PMEMORYMODULE)mod;
  789. if (module == NULL || module->isDLL || module->exeEntry == NULL || !module->isRelocated) {
  790. return -1;
  791. }
  792. return module->exeEntry();
  793. }
  794. #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
  795. HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type)
  796. {
  797. return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE);
  798. }
  799. static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(
  800. void *root,
  801. PIMAGE_RESOURCE_DIRECTORY resources,
  802. LPCTSTR key)
  803. {
  804. PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resources + 1);
  805. PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL;
  806. DWORD start;
  807. DWORD end;
  808. DWORD middle;
  809. if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) {
  810. // special case: resource id given as string
  811. TCHAR *endpos = NULL;
  812. long int tmpkey = (WORD) _tcstol((TCHAR *) &key[1], &endpos, 10);
  813. if (tmpkey <= 0xffff && lstrlen(endpos) == 0) {
  814. key = MAKEINTRESOURCE(tmpkey);
  815. }
  816. }
  817. // entries are stored as ordered list of named entries,
  818. // followed by an ordered list of id entries - we can do
  819. // a binary search to find faster...
  820. if (IS_INTRESOURCE(key)) {
  821. WORD check = (WORD) (uintptr_t) key;
  822. start = resources->NumberOfNamedEntries;
  823. end = start + resources->NumberOfIdEntries;
  824. while (end > start) {
  825. WORD entryName;
  826. middle = (start + end) >> 1;
  827. entryName = (WORD) entries[middle].Name;
  828. if (check < entryName) {
  829. end = (end != middle ? middle : middle-1);
  830. } else if (check > entryName) {
  831. start = (start != middle ? middle : middle+1);
  832. } else {
  833. result = &entries[middle];
  834. break;
  835. }
  836. }
  837. } else {
  838. LPCWSTR searchKey;
  839. size_t searchKeyLen = _tcslen(key);
  840. #if defined(UNICODE)
  841. searchKey = key;
  842. #else
  843. // Resource names are always stored using 16bit characters, need to
  844. // convert string we search for.
  845. #define MAX_LOCAL_KEY_LENGTH 2048
  846. // In most cases resource names are short, so optimize for that by
  847. // using a pre-allocated array.
  848. wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH+1];
  849. LPWSTR _searchKey;
  850. if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) {
  851. size_t _searchKeySize = (searchKeyLen + 1) * sizeof(wchar_t);
  852. _searchKey = (LPWSTR) malloc(_searchKeySize);
  853. if (_searchKey == NULL) {
  854. SetLastError(ERROR_OUTOFMEMORY);
  855. return NULL;
  856. }
  857. } else {
  858. _searchKey = &_searchKeySpace[0];
  859. }
  860. mbstowcs(_searchKey, key, searchKeyLen);
  861. _searchKey[searchKeyLen] = 0;
  862. searchKey = _searchKey;
  863. #endif
  864. start = 0;
  865. end = resources->NumberOfNamedEntries;
  866. while (end > start) {
  867. int cmp;
  868. PIMAGE_RESOURCE_DIR_STRING_U resourceString;
  869. middle = (start + end) >> 1;
  870. resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(root, entries[middle].Name & 0x7FFFFFFF);
  871. cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length);
  872. if (cmp == 0) {
  873. // Handle partial match
  874. if (searchKeyLen > resourceString->Length) {
  875. cmp = 1;
  876. } else if (searchKeyLen < resourceString->Length) {
  877. cmp = -1;
  878. }
  879. }
  880. if (cmp < 0) {
  881. end = (middle != end ? middle : middle-1);
  882. } else if (cmp > 0) {
  883. start = (middle != start ? middle : middle+1);
  884. } else {
  885. result = &entries[middle];
  886. break;
  887. }
  888. }
  889. #if !defined(UNICODE)
  890. if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) {
  891. free(_searchKey);
  892. }
  893. #undef MAX_LOCAL_KEY_LENGTH
  894. #endif
  895. }
  896. return result;
  897. }
  898. HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language)
  899. {
  900. unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase;
  901. PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE) module, IMAGE_DIRECTORY_ENTRY_RESOURCE);
  902. PIMAGE_RESOURCE_DIRECTORY rootResources;
  903. PIMAGE_RESOURCE_DIRECTORY nameResources;
  904. PIMAGE_RESOURCE_DIRECTORY typeResources;
  905. PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType;
  906. PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName;
  907. PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage;
  908. if (directory->Size == 0) {
  909. // no resource table found
  910. SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
  911. return NULL;
  912. }
  913. if (language == DEFAULT_LANGUAGE) {
  914. // use language from current thread
  915. language = LANGIDFROMLCID(GetThreadLocale());
  916. }
  917. // resources are stored as three-level tree
  918. // - first node is the type
  919. // - second node is the name
  920. // - third node is the language
  921. rootResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress);
  922. foundType = _MemorySearchResourceEntry(rootResources, rootResources, type);
  923. if (foundType == NULL) {
  924. SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND);
  925. return NULL;
  926. }
  927. typeResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff));
  928. foundName = _MemorySearchResourceEntry(rootResources, typeResources, name);
  929. if (foundName == NULL) {
  930. SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
  931. return NULL;
  932. }
  933. nameResources = (PIMAGE_RESOURCE_DIRECTORY) (codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff));
  934. foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR) (uintptr_t) language);
  935. if (foundLanguage == NULL) {
  936. // requested language not found, use first available
  937. if (nameResources->NumberOfIdEntries == 0) {
  938. SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND);
  939. return NULL;
  940. }
  941. foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1);
  942. }
  943. return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff));
  944. }
  945. DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource)
  946. {
  947. PIMAGE_RESOURCE_DATA_ENTRY entry;
  948. UNREFERENCED_PARAMETER(module);
  949. entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource;
  950. if (entry == NULL) {
  951. return 0;
  952. }
  953. return entry->Size;
  954. }
  955. LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource)
  956. {
  957. unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase;
  958. PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource;
  959. if (entry == NULL) {
  960. return NULL;
  961. }
  962. return codeBase + entry->OffsetToData;
  963. }
  964. int
  965. MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize)
  966. {
  967. return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE);
  968. }
  969. int
  970. MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language)
  971. {
  972. HMEMORYRSRC resource;
  973. PIMAGE_RESOURCE_DIR_STRING_U data;
  974. DWORD size;
  975. if (maxsize == 0) {
  976. return 0;
  977. }
  978. resource = MemoryFindResourceEx(module, MAKEINTRESOURCE((id >> 4) + 1), RT_STRING, language);
  979. if (resource == NULL) {
  980. buffer[0] = 0;
  981. return 0;
  982. }
  983. data = (PIMAGE_RESOURCE_DIR_STRING_U) MemoryLoadResource(module, resource);
  984. id = id & 0x0f;
  985. while (id--) {
  986. data = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(data, (data->Length + 1) * sizeof(WCHAR));
  987. }
  988. if (data->Length == 0) {
  989. SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
  990. buffer[0] = 0;
  991. return 0;
  992. }
  993. size = data->Length;
  994. if (size >= (DWORD) maxsize) {
  995. size = maxsize;
  996. } else {
  997. buffer[size] = 0;
  998. }
  999. #pragma warning(disable:4996)
  1000. #if defined(UNICODE)
  1001. wcsncpy(buffer, data->NameString, size);
  1002. #else
  1003. wcstombs(buffer, data->NameString, size);
  1004. #endif
  1005. return size;
  1006. }
  1007. #ifdef TESTSUITE
  1008. #include <stdio.h>
  1009. #ifndef PRIxPTR
  1010. #ifdef _WIN64
  1011. #define PRIxPTR "I64x"
  1012. #else
  1013. #define PRIxPTR "x"
  1014. #endif
  1015. #endif
  1016. static const uintptr_t AlignValueDownTests[][3] = {
  1017. {16, 16, 16},
  1018. {17, 16, 16},
  1019. {32, 16, 32},
  1020. {33, 16, 32},
  1021. #ifdef _WIN64
  1022. {0x12345678abcd1000, 0x1000, 0x12345678abcd1000},
  1023. {0x12345678abcd101f, 0x1000, 0x12345678abcd1000},
  1024. #endif
  1025. {0, 0, 0},
  1026. };
  1027. static const uintptr_t AlignValueUpTests[][3] = {
  1028. {16, 16, 16},
  1029. {17, 16, 32},
  1030. {32, 16, 32},
  1031. {33, 16, 48},
  1032. #ifdef _WIN64
  1033. {0x12345678abcd1000, 0x1000, 0x12345678abcd1000},
  1034. {0x12345678abcd101f, 0x1000, 0x12345678abcd2000},
  1035. #endif
  1036. {0, 0, 0},
  1037. };
  1038. BOOL MemoryModuleTestsuite() {
  1039. BOOL success = TRUE;
  1040. size_t idx;
  1041. for (idx = 0; AlignValueDownTests[idx][0]; ++idx) {
  1042. const uintptr_t* tests = AlignValueDownTests[idx];
  1043. uintptr_t value = AlignValueDown(tests[0], tests[1]);
  1044. if (value != tests[2]) {
  1045. printf("AlignValueDown failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n",
  1046. tests[0], tests[1], tests[2], value);
  1047. success = FALSE;
  1048. }
  1049. }
  1050. for (idx = 0; AlignValueDownTests[idx][0]; ++idx) {
  1051. const uintptr_t* tests = AlignValueUpTests[idx];
  1052. uintptr_t value = AlignValueUp(tests[0], tests[1]);
  1053. if (value != tests[2]) {
  1054. printf("AlignValueUp failed for 0x%" PRIxPTR "/0x%" PRIxPTR ": expected 0x%" PRIxPTR ", got 0x%" PRIxPTR "\n",
  1055. tests[0], tests[1], tests[2], value);
  1056. success = FALSE;
  1057. }
  1058. }
  1059. if (success) {
  1060. printf("OK\n");
  1061. }
  1062. return success;
  1063. }
  1064. #endif