PageRenderTime 33ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/PortableExecutable.cpp

https://bitbucket.org/BlackLuny/crysearch-memory-scanner
C++ | 2276 lines | 1559 code | 364 blank | 353 comment | 302 complexity | 38c298094121c242bcddc7a5039cd75d MD5 | raw file
  1. #include "PortableExecutable.h"
  2. #include "BackendGlobalDef.h"
  3. // Defines seperately because the Windows SDK 7.1 headers do not yet include these two.
  4. #define _WIN32_WINNT_WIN8 0x0602
  5. #define _WIN32_WINNT_WINBLUE 0x0603
  6. #include <Shlwapi.h>
  7. #pragma comment(lib, "shlwapi.lib")
  8. #define EAT_ADDRESS_NOT_FOUND -1
  9. #define THREAD_HIJACK_MAGIC_PROBE_THRESHOLD 12
  10. // Checks whether a RVA points inside a section of the executable. Returns true if so and false if not.
  11. const bool RVAPointsInsideSection(const DWORD rva)
  12. {
  13. // Walk the sections in the target process.
  14. for (auto const& section : LoadedProcessPEInformation.ImageSections)
  15. {
  16. // Check if the specified RVA is within the bounds of a section.
  17. if (rva > section.BaseAddress && rva < (section.BaseAddress + section.RawSectionSize))
  18. {
  19. return true;
  20. }
  21. }
  22. return false;
  23. }
  24. // -------------------------------------------------------------------------------------------------------------------------------
  25. // Base class methods
  26. // -------------------------------------------------------------------------------------------------------------------------------
  27. // Default PE class constructor.
  28. PortableExecutable::PortableExecutable()
  29. {
  30. this->mProcessHandle = mMemoryScanner->GetHandle();
  31. this->mBaseAddress = mModuleManager->GetBaseAddress();
  32. }
  33. // Default PE class destructor. Virtual destructor, always use derived class' destructor to execute this one.
  34. PortableExecutable::~PortableExecutable()
  35. {
  36. LoadedProcessPEInformation.PEFields.Clear();
  37. LoadedProcessPEInformation.Reset();
  38. LoadedProcessPEInformation.ClearImportTable();
  39. }
  40. // Sets the base address.
  41. void PortableExecutable::SetBaseAddress(const SIZE_T baseAddress)
  42. {
  43. this->mBaseAddress = baseAddress;
  44. }
  45. // Gets the base address.
  46. const SIZE_T PortableExecutable::GetBaseAddress() const
  47. {
  48. return this->mBaseAddress;
  49. }
  50. // Retrieves the address of the Process Environment Block of the opened process.
  51. // Returns the PEB base address or NULL if the address was not succesfully retrieved.
  52. void* PortableExecutable::GetPebAddress() const
  53. {
  54. #ifdef WIN64
  55. if (mMemoryScanner->IsX86Process())
  56. {
  57. // If we run CrySearch x64 and we target an x86 process, we use NtQueryInformationProcess with a ULONG_PTR parameter.
  58. ULONG_PTR PebBaseAddress;
  59. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessWow64Information, &PebBaseAddress, sizeof(ULONG_PTR), NULL) == STATUS_SUCCESS)
  60. {
  61. return (void*)PebBaseAddress;
  62. }
  63. }
  64. else
  65. {
  66. // If we run CrySearch x64 and we target an x64 process, we use NtQueryInformationProcess with a PROCESS_BASIC_INFORMATION parameter.
  67. PROCESS_BASIC_INFORMATION tInfo;
  68. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessBasicInformation, &tInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL) == STATUS_SUCCESS)
  69. {
  70. return tInfo.PebBaseAddress;
  71. }
  72. }
  73. #else
  74. // If we run CrySearch x86, we can only target an x86 process and we use NtQueryInformationProcess with a PROCESS_BASIC_INFORMATION parameter.
  75. PROCESS_BASIC_INFORMATION tInfo;
  76. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessBasicInformation, &tInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL) == STATUS_SUCCESS)
  77. {
  78. return tInfo.PebBaseAddress;
  79. }
  80. #endif
  81. return NULL;
  82. }
  83. // Parses input machine type and adds the parsed value to the global inventory for UI display.
  84. void PortableExecutable::ParseMachineType(const DWORD machineType) const
  85. {
  86. switch (machineType)
  87. {
  88. case IMAGE_FILE_MACHINE_I386:
  89. LoadedProcessPEInformation.PEFields.Add("Machine Type", "i386");
  90. break;
  91. case IMAGE_FILE_MACHINE_IA64:
  92. LoadedProcessPEInformation.PEFields.Add("Machine Type", "ia64");
  93. break;
  94. case IMAGE_FILE_MACHINE_AMD64:
  95. LoadedProcessPEInformation.PEFields.Add("Machine Type", "amd64");
  96. break;
  97. }
  98. }
  99. // Parses input subsystem type and adds the parsed value to the global inventory for UI display.
  100. void PortableExecutable::ParseSubsystemValue(const DWORD subSystem) const
  101. {
  102. switch (subSystem)
  103. {
  104. case IMAGE_SUBSYSTEM_UNKNOWN:
  105. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Unknown");
  106. break;
  107. case IMAGE_SUBSYSTEM_NATIVE:
  108. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Native");
  109. break;
  110. case IMAGE_SUBSYSTEM_WINDOWS_GUI:
  111. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Windows GUI");
  112. break;
  113. case IMAGE_SUBSYSTEM_WINDOWS_CUI:
  114. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Windows CUI");
  115. break;
  116. case IMAGE_SUBSYSTEM_OS2_CUI:
  117. LoadedProcessPEInformation.PEFields.Add("Subsystem", "OS/2 CUI");
  118. break;
  119. case IMAGE_SUBSYSTEM_POSIX_CUI:
  120. LoadedProcessPEInformation.PEFields.Add("Subsystem", "POSIX_CUI");
  121. break;
  122. case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
  123. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Windows CE CUI");
  124. break;
  125. case IMAGE_SUBSYSTEM_EFI_APPLICATION:
  126. LoadedProcessPEInformation.PEFields.Add("Subsystem", "EFI");
  127. break;
  128. case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
  129. LoadedProcessPEInformation.PEFields.Add("Subsystem", "EFI Boot Driver");
  130. break;
  131. case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
  132. LoadedProcessPEInformation.PEFields.Add("Subsystem", "EFI Runtime Driver");
  133. break;
  134. case IMAGE_SUBSYSTEM_EFI_ROM:
  135. LoadedProcessPEInformation.PEFields.Add("Subsystem", "EFI ROM");
  136. break;
  137. case IMAGE_SUBSYSTEM_XBOX:
  138. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Xbox system");
  139. break;
  140. case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
  141. LoadedProcessPEInformation.PEFields.Add("Subsystem", "Boot application");
  142. break;
  143. }
  144. }
  145. // This function retrieves all sections from a specified PE file. The NT header is provided to create flexibility.
  146. // The input list is cleared before the retrieval is started.
  147. void PortableExecutable::GetImageSectionsList(const IMAGE_SECTION_HEADER* pSecHeader, const DWORD numberOfSections, Vector<Win32PESectionInformation>& list) const
  148. {
  149. list.Clear();
  150. // Iterate through sections and save them for application use.
  151. for (unsigned int i = 0; i < numberOfSections; ++i, ++pSecHeader)
  152. {
  153. // Sometimes PE files contain bogus sections at runtime due to packer activities. Remove bogus sections from the list.
  154. if (!pSecHeader->VirtualAddress)
  155. {
  156. continue;
  157. }
  158. // The name of a section can only be 8 characters long. A longer name has a different notation.
  159. // This is not taken into account because the chance of it appearing in an executable is very small.
  160. list.Add(Win32PESectionInformation((char*)pSecHeader->Name, pSecHeader->VirtualAddress, pSecHeader->Misc.VirtualSize == 0 ? pSecHeader->SizeOfRawData
  161. : pSecHeader->Misc.VirtualSize, pSecHeader->SizeOfRawData));
  162. }
  163. }
  164. // This function is declared seperately to reduce code in a few functions spreaded over this file.
  165. // This increases the code readability even though the function will probably be inlined by the compiler.
  166. wchar* PortableExecutable::InlineResolveApiSetSchema(const WString& str) const
  167. {
  168. // Check which version of Windows is running. We need this to differentiate between ApiSetSchema versions.
  169. Tuple2<int, int> winver;
  170. if (GetInlineWindowsVersion(&winver))
  171. {
  172. // Call the correct ApiSetSchema parsing function.
  173. if (winver.a == 6)
  174. {
  175. if (winver.b == 4)
  176. {
  177. // Call the Windows 10 version of the parser.
  178. return this->ResolveApiSetSchemaMapping10(str, str.GetLength());
  179. }
  180. else if (winver.b > 2)
  181. {
  182. // Call the Windows 8(.1) version of the parser.
  183. return this->ResolveApiSetSchemaMappingEx(str, str.GetLength());
  184. }
  185. else
  186. {
  187. // Call the Windows 7 version of the parser.
  188. return this->ResolveApiSetSchemaMapping(str, str.GetLength());
  189. }
  190. }
  191. else if (winver.a == 10)
  192. {
  193. // Call the Windows 10 version of the parser.
  194. return this->ResolveApiSetSchemaMapping10(str, str.GetLength());
  195. }
  196. }
  197. return NULL;
  198. }
  199. // Resolves Windows 6.x ApiSetSchema redirections found in the IAT. Usually they redirect to a common Windows DLL like advapi32.dll.
  200. // Returns the name of the redirected library, or NULL if the function failed. Beware that you still need to delete the buffer assigned to the return value!
  201. wchar* PortableExecutable::ResolveApiSetSchemaMapping(const wchar* ApiSetSchemaDll, const DWORD Length) const
  202. {
  203. // Retrieve PEB, the address of the map is there.
  204. #ifdef _WIN64
  205. APISETMAP* const apiSetSchemaBase = (APISETMAP*)((PPEB)__readgsqword(0x60))->ApiSetMap;
  206. #else
  207. APISETMAP* const apiSetSchemaBase = (APISETMAP*)((PPEB)__readfsdword(0x30))->ApiSetMap;
  208. #endif
  209. Byte* const apiSetSchemaFileBuffer = (Byte*)apiSetSchemaBase;
  210. DLLHOSTDESCRIPTOR* pDescriptor = apiSetSchemaBase->descriptors;
  211. // Iterate through the descriptor structs.
  212. for (unsigned int i = 0; i < apiSetSchemaBase->NumberOfHosts; ++i, ++pDescriptor)
  213. {
  214. // Compare virtual API with input.
  215. if (_wcsnicmp(ApiSetSchemaDll, (wchar*)(apiSetSchemaFileBuffer + pDescriptor->OffsetDllString), Length) == 0)
  216. {
  217. DLLREDIRECTOR* const directorStruct = (DLLREDIRECTOR*)(apiSetSchemaFileBuffer + pDescriptor->OffsetDllRedirector);
  218. // Iterate redirections for this api set.
  219. REDIRECTION* pRedirectionDescriptor = directorStruct->Redirection;
  220. const wchar* const redirectionString = (wchar*)(apiSetSchemaFileBuffer + pRedirectionDescriptor->OffsetRedirection2);
  221. // Redirection is found, create buffer to return to the caller and copy the logical dll name into it.
  222. const DWORD wcsLength = pRedirectionDescriptor->RedirectionLength2 / 2;
  223. wchar* const nameBuffer = new wchar[wcsLength + 1];
  224. memcpy(nameBuffer, redirectionString, pRedirectionDescriptor->RedirectionLength2);
  225. // Set null terminator in the string, otherwise the result contains the redirected dll name but the rest is undefined.
  226. nameBuffer[wcsLength] = NULL;
  227. return nameBuffer;
  228. }
  229. }
  230. return NULL;
  231. }
  232. // Compatibility with Windows 8.1 ApiSetSchema v2 is implemented since v1.04 of CrySearch.
  233. // Return value is the same as the PortableExecutable::ResolveApiSetSchemaMapping function.
  234. wchar* PortableExecutable::ResolveApiSetSchemaMappingEx(const wchar* ApiSetSchemaDll, const DWORD Length) const
  235. {
  236. // Retrieve PEB, the address of the map is there.
  237. #ifdef _WIN64
  238. API_SET_NAMESPACE_ARRAY_V2* const apiSetSchemaBase = (API_SET_NAMESPACE_ARRAY_V2*)((PPEB)__readgsqword(0x60))->ApiSetMap;
  239. #else
  240. API_SET_NAMESPACE_ARRAY_V2* const apiSetSchemaBase = (API_SET_NAMESPACE_ARRAY_V2*)((PPEB)__readfsdword(0x30))->ApiSetMap;
  241. #endif
  242. Byte* const apiSetSchemaFileBuffer = (Byte*)apiSetSchemaBase;
  243. API_SET_NAMESPACE_ENTRY_V2* pDescriptor = apiSetSchemaBase->Array;
  244. // Iterate through the descriptor structs.
  245. for (unsigned int i = 0; i < apiSetSchemaBase->Count; ++i, ++pDescriptor)
  246. {
  247. // Compare virtual API with input.
  248. if (_wcsnicmp(ApiSetSchemaDll, (wchar*)(apiSetSchemaFileBuffer + pDescriptor->NameOffset), Length) == 0)
  249. {
  250. API_SET_VALUE_ARRAY_V2* const directorStruct = (API_SET_VALUE_ARRAY_V2*)(apiSetSchemaFileBuffer + pDescriptor->DataOffset);
  251. // Iterate redirections for this api set.
  252. API_SET_VALUE_ENTRY_V2* pRedirectionDescriptor = directorStruct->Array;
  253. const wchar* const redirectionString = (wchar*)(apiSetSchemaFileBuffer + pRedirectionDescriptor->ValueOffset);
  254. // Apparently a virtual library may have two redirections. If the library being
  255. // processed matches the first API redirection, we must use the second one.
  256. const unsigned int totalLengthW = (unsigned int)wcslen(redirectionString);
  257. const DWORD wcsIndex = pRedirectionDescriptor->ValueLength / sizeof(wchar);
  258. wchar* const nameBuffer = new wchar[totalLengthW * sizeof(wchar)];
  259. if (_wcsnicmp(ApiSetSchemaDll, redirectionString + 4, Length) == 0)
  260. {
  261. // Redirection is found, create buffer to return to the caller and copy the logical dll name into it.
  262. const DWORD wcharCount = totalLengthW - wcsIndex;
  263. memcpy(nameBuffer, redirectionString + wcsIndex, wcharCount);
  264. nameBuffer[wcharCount] = NULL;
  265. }
  266. else
  267. {
  268. // Take the first redirection as result.
  269. memcpy(nameBuffer, redirectionString, pRedirectionDescriptor->ValueLength);
  270. nameBuffer[pRedirectionDescriptor->ValueLength / sizeof(wchar)] = NULL;
  271. }
  272. return nameBuffer;
  273. }
  274. }
  275. return NULL;
  276. }
  277. // Compatibility with Windows 10 ApiSetSchema is implemented since v2.0 of CrySearch.
  278. // Return value is the same as the PortableExecutable::ResolveApiSetSchemaMapping function.
  279. wchar* PortableExecutable::ResolveApiSetSchemaMapping10(const wchar* ApiSetSchemaDll, const DWORD Length ) const
  280. {
  281. // Retrieve PEB, the address of the map is there.
  282. #ifdef _WIN64
  283. API_SET_NAMESPACE_ARRAY_10* const apiSetSchemaBase = (API_SET_NAMESPACE_ARRAY_10*)((PPEB)__readgsqword(0x60))->ApiSetMap;
  284. #else
  285. API_SET_NAMESPACE_ARRAY_10* const apiSetSchemaBase = (API_SET_NAMESPACE_ARRAY_10*)((PPEB)__readfsdword(0x30))->ApiSetMap;
  286. #endif
  287. Byte* const apiSetSchemaFileBuffer = (Byte*)apiSetSchemaBase;
  288. API_SET_NAMESPACE_ENTRY_10* pDescriptor = (API_SET_NAMESPACE_ENTRY_10*)(apiSetSchemaFileBuffer + apiSetSchemaBase->End);
  289. // Iterate through the descriptor structs.
  290. for (unsigned int i = 0; i < apiSetSchemaBase->Count; ++i, ++pDescriptor)
  291. {
  292. // Retrieve the data associated with the current ApiSet schema entry.
  293. API_SET_VALUE_ARRAY_10* const directorStruct = (API_SET_VALUE_ARRAY_10*)(apiSetSchemaFileBuffer + apiSetSchemaBase->Start + sizeof(API_SET_VALUE_ARRAY_10) * pDescriptor->Size);
  294. // Compare virtual API with input. We need to add 4 words to the pointer because in Windows 10, the API names are not truncated to 'ms-win...'.
  295. if (_wcsnicmp(ApiSetSchemaDll, (wchar*)(apiSetSchemaFileBuffer + directorStruct->NameOffset + 8), Length - 1) == 0)
  296. {
  297. // Iterate redirections for this api set.
  298. API_SET_VALUE_ENTRY_10* pRedirectionDescriptor = (API_SET_VALUE_ENTRY_10*)(apiSetSchemaFileBuffer + directorStruct->DataOffset);
  299. const wchar* const redirectionString = (wchar*)(apiSetSchemaFileBuffer + pRedirectionDescriptor->ValueOffset);
  300. // Apparently a virtual library may have two redirections. If the library being
  301. // processed matches the first API redirection, we must use the second one.
  302. const unsigned int totalLengthW = (unsigned int)wcslen(redirectionString);
  303. const DWORD wcsIndex = pRedirectionDescriptor->ValueLength / sizeof(wchar);
  304. wchar* const nameBuffer = new wchar[totalLengthW * sizeof(wchar)];
  305. if (_wcsnicmp(ApiSetSchemaDll, redirectionString + 4, Length) == 0)
  306. {
  307. // Redirection is found, create buffer to return to the caller and copy the logical dll name into it.
  308. const DWORD wcharCount = totalLengthW - wcsIndex;
  309. memcpy(nameBuffer, redirectionString + wcsIndex, wcharCount);
  310. nameBuffer[wcharCount] = NULL;
  311. }
  312. else
  313. {
  314. // Take the first redirection as result.
  315. memcpy(nameBuffer, redirectionString, pRedirectionDescriptor->ValueLength);
  316. nameBuffer[pRedirectionDescriptor->ValueLength / sizeof(wchar)] = NULL;
  317. }
  318. return nameBuffer;
  319. }
  320. }
  321. return NULL;
  322. }
  323. // Reads the COM directory from a PE file header. Most likely this is the .NET header.
  324. // This function does not free the buffer pointed to by the parameter.
  325. void PortableExecutable::GetDotNetDirectoryInformation(const IMAGE_DATA_DIRECTORY* const netHeader) const
  326. {
  327. // Check if the executable contains a COM header.
  328. if (netHeader->VirtualAddress && netHeader->Size >= sizeof(IMAGE_COR20_HEADER))
  329. {
  330. SIZE_T bytesRead;
  331. // Read COR20 header from file.
  332. Byte* netDirBuffer = new Byte[netHeader->Size];
  333. bool b = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + netHeader->VirtualAddress), netDirBuffer, netHeader->Size, &bytesRead);
  334. // Check if the section data was read succesfully.
  335. if (b && bytesRead == netHeader->Size)
  336. {
  337. // Save version information from COR20 header.
  338. IMAGE_DATA_DIRECTORY mdDir;
  339. memcpy(&mdDir, &((IMAGE_COR20_HEADER*)netDirBuffer)->MetaData, sizeof(IMAGE_DATA_DIRECTORY));
  340. delete[] netDirBuffer;
  341. // Save the offset to the metadata header to allow dumping of .NET sections later.
  342. LoadedProcessPEInformation.DotNetInformation.MetadataHeaderOffset = mdDir.VirtualAddress;
  343. // Read metadata from header.
  344. netDirBuffer = new Byte[mdDir.Size];
  345. b = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + mdDir.VirtualAddress), netDirBuffer, mdDir.Size, &bytesRead);
  346. // Check whether the metadata was succesfully read into the local buffer.
  347. if (b && bytesRead == mdDir.Size)
  348. {
  349. // Dissect metadata. Since its a dynamic structure we cannot compile this into a struct.
  350. const DWORD vStrLength = *(DWORD*)(netDirBuffer + 12);
  351. const WORD streamCount = *(WORD*)(netDirBuffer + 18 + vStrLength);
  352. // Based on the stream count, dissect streams from the header.
  353. DWORD streamIterator = 0;
  354. for (const char* iterator = (char*)(netDirBuffer + 20 + vStrLength); streamIterator < streamCount; ++streamIterator)
  355. {
  356. // Get offset and size fields.
  357. const DWORD* const offsetPtr = (DWORD*)iterator;
  358. iterator += sizeof(DWORD);
  359. const DWORD* const sizePtr = (DWORD*)iterator;
  360. iterator += sizeof(DWORD);
  361. // Read the name of the stream.
  362. WORD str = 0;
  363. const char* const beginIterator = iterator;
  364. bool strEnded = false;
  365. while (1)
  366. {
  367. // First find the end of the string.
  368. if (!strEnded && *iterator == 0)
  369. {
  370. strEnded = true;
  371. }
  372. // Continue until the next 4 byte boundary is reached.
  373. else if (strEnded && ((SIZE_T)iterator % 4) == 0)
  374. {
  375. break;
  376. }
  377. ++str;
  378. ++iterator;
  379. }
  380. // String length was measured, now read it into a variable.
  381. Win32DotNetSectionInformation& newSect = LoadedProcessPEInformation.DotNetInformation.DotNetSections.Add();
  382. newSect.SectionName = String(beginIterator, str + 1);
  383. newSect.Offset = *offsetPtr;
  384. newSect.Size = *sizePtr;
  385. }
  386. }
  387. }
  388. delete[] netDirBuffer;
  389. }
  390. }
  391. // Resolves ApiSetSchema module names and returns a pointer to the resolved module.
  392. const Win32ModuleInformation* PortableExecutable::GetResolvedModule(const char* pModName, int* const recurseIndex, const char* NameOrdinal) const
  393. {
  394. // Find the first dot in the filename.
  395. String forwardedModName = pModName;
  396. *recurseIndex = forwardedModName.Find('.');
  397. // If the resulting filename starts with api-ms-win, we are dealing with ApiSetSchema libraries.
  398. WString apiSetDllName = ToLower(forwardedModName);
  399. if (apiSetDllName.StartsWith("api-ms-win") || apiSetDllName.StartsWith("ext-ms-win"))
  400. {
  401. apiSetDllName.Remove(0, 4);
  402. apiSetDllName.Remove(apiSetDllName.Find('.'), (int)strlen(NameOrdinal) + 1);
  403. const wchar* const outWString = this->InlineResolveApiSetSchema(apiSetDllName);
  404. forwardedModName = WString(outWString).ToString();
  405. delete[] outWString;
  406. }
  407. // Append .dll after the filename.
  408. const int dotIndex = forwardedModName.Find('.');
  409. if (dotIndex >= 0)
  410. {
  411. forwardedModName.Remove(dotIndex, forwardedModName.GetLength() - dotIndex);
  412. forwardedModName += ".dll";
  413. }
  414. // Resolve the module to a loaded one.
  415. return mModuleManager->FindModule(forwardedModName);
  416. }
  417. // -------------------------------------------------------------------------------------------------------------------------------
  418. // PE32 class methods
  419. // -------------------------------------------------------------------------------------------------------------------------------
  420. // Default PE32 destructor. Base class destructor is virtual so this destructor is executed with the base's.
  421. PortableExecutable32::~PortableExecutable32()
  422. {
  423. }
  424. // Retrieves PE header information from the loaded process. Information is saved in global storage that has process lifetime.
  425. // Note that IMAGE_NT_HEADERS and IMAGE_OPTIONAL_HEADER are explicitly defined as the 32 bit version. If compiled as 64 bit the structs differ.
  426. void PortableExecutable32::GetExecutablePeInformation() const
  427. {
  428. // Clear image sections before getting new ones.
  429. LoadedProcessPEInformation.Reset();
  430. // Read process memory into local buffer in order to load PE headers.
  431. Byte moduleBuffer[0x400];
  432. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, 0x400, NULL);
  433. // Load PE headers.
  434. IMAGE_DOS_HEADER* const pDosHeader = (IMAGE_DOS_HEADER*)moduleBuffer;
  435. IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(moduleBuffer + pDosHeader->e_lfanew);
  436. // When the PE Headers are destroyed at runtime the pointer to the headers may run out of the buffer's bounds.
  437. if ((Byte*)pNTHeader > (moduleBuffer + 0x400))
  438. {
  439. LoadedProcessPEInformation.PEFields.Clear();
  440. return;
  441. }
  442. // The headers should be fine, proceed loading the optional and file header.
  443. const IMAGE_OPTIONAL_HEADER32* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader;
  444. const IMAGE_FILE_HEADER* const pFileHeader = &(pNTHeader->FileHeader);
  445. // Retrieve the type of machine the PE executable can run on.
  446. this->ParseMachineType(pFileHeader->Machine);
  447. // Retrieve PE fields and add them to the map.
  448. LoadedProcessPEInformation.PEFields.Add("Number of sections", pFileHeader->NumberOfSections);
  449. LoadedProcessPEInformation.PEFields.Add("Size of optional header", Format("%X", pFileHeader->SizeOfOptionalHeader));
  450. LoadedProcessPEInformation.PEFields.Add("Pointer to symbol table", (int)pFileHeader->PointerToSymbolTable);
  451. LoadedProcessPEInformation.PEFields.Add("Number of symbols", (int)pFileHeader->NumberOfSymbols);
  452. LoadedProcessPEInformation.PEFields.Add("Image base", Format("%lX", (int)pOptionalHeader->ImageBase));
  453. #ifndef _WIN64
  454. LoadedProcessPEInformation.PEFields.Add("Base of data", Format("%lX", (int)pOptionalHeader->BaseOfData));
  455. #endif
  456. LoadedProcessPEInformation.PEFields.Add("Base of code", Format("%lX", (int)pOptionalHeader->BaseOfCode));
  457. LoadedProcessPEInformation.PEFields.Add("Address of entrypoint", Format("%lX", (int)pOptionalHeader->AddressOfEntryPoint));
  458. LoadedProcessPEInformation.PEFields.Add("Size of code", Format("%lX", (int)pOptionalHeader->SizeOfCode));
  459. LoadedProcessPEInformation.PEFields.Add("Size of initialized data", Format("%lX", (int)pOptionalHeader->SizeOfInitializedData));
  460. LoadedProcessPEInformation.PEFields.Add("Size of uninitialized data", Format("%lX", (int)pOptionalHeader->SizeOfUninitializedData));
  461. LoadedProcessPEInformation.PEFields.Add("Section alignment", Format("%lX", (int)pOptionalHeader->SectionAlignment));
  462. LoadedProcessPEInformation.PEFields.Add("File alignment", Format("%lX", (int)pOptionalHeader->FileAlignment));
  463. LoadedProcessPEInformation.PEFields.Add("Size of image", Format("%lX", (int)pOptionalHeader->SizeOfImage));
  464. LoadedProcessPEInformation.PEFields.Add("Size of headers", Format("%lX", (int)pOptionalHeader->SizeOfHeaders));
  465. LoadedProcessPEInformation.PEFields.Add("Checksum", Format("%lX", (int)pOptionalHeader->CheckSum));
  466. LoadedProcessPEInformation.PEFields.Add("Linker version", Format("%i.%i", pOptionalHeader->MajorLinkerVersion, pOptionalHeader->MinorLinkerVersion));
  467. LoadedProcessPEInformation.PEFields.Add("OS version", Format("%i.%i", pOptionalHeader->MajorOperatingSystemVersion, pOptionalHeader->MinorOperatingSystemVersion));
  468. LoadedProcessPEInformation.PEFields.Add("Image version", Format("%i.%i", pOptionalHeader->MajorImageVersion, pOptionalHeader->MinorImageVersion));
  469. LoadedProcessPEInformation.PEFields.Add("Subsystem version", Format("%i.%i", pOptionalHeader->MajorSubsystemVersion, pOptionalHeader->MinorSubsystemVersion));
  470. LoadedProcessPEInformation.PEFields.Add("Number of data directories", Format("%lX", (int)pOptionalHeader->NumberOfRvaAndSizes));
  471. // Parse the last general property value of the PE header, save the section values and destroy the buffer.
  472. this->ParseSubsystemValue(pOptionalHeader->Subsystem);
  473. const DWORD sectionCount = pNTHeader->FileHeader.NumberOfSections;
  474. const DWORD sectionSizeBytes = sizeof(IMAGE_SECTION_HEADER) * sectionCount;
  475. const IMAGE_SECTION_HEADER* const firstSectionPtr = (IMAGE_SECTION_HEADER*)(this->mBaseAddress + ((Byte*)IMAGE_FIRST_SECTION(pNTHeader) - moduleBuffer));
  476. // Get the COM header from the PE file.
  477. this->GetDotNetDirectoryInformation(&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]);
  478. // Attempt to load the sections inside the PE file.
  479. Byte* const sectionBuffer = new Byte[sectionSizeBytes];
  480. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, firstSectionPtr, sectionBuffer, sectionSizeBytes, NULL);
  481. this->GetImageSectionsList((IMAGE_SECTION_HEADER*)sectionBuffer, sectionCount, LoadedProcessPEInformation.ImageSections);
  482. delete[] sectionBuffer;
  483. }
  484. // Retrieves the address of a function in the export table of a module. Address can be returned for function by name or ordinal.
  485. // Returns the address of the function, created from the module base address added by the function RVA.
  486. // If the function is not found, the return value is 0xFFFFFFFF.
  487. // The NameLength parameter contains the length of the name if there is a name, or 0 if the function is ordinal-based.
  488. SIZE_T PortableExecutable32::GetAddressFromExportTable(const AddrStruct* addr, const char* NameOrdinal, const unsigned int NameLength) const
  489. {
  490. if (addr->ExportDirectory->AddressOfNameOrdinals)
  491. {
  492. int ResurseDotIndex = 0;
  493. const DWORD* funcAddrPtr = NULL;
  494. bool b;
  495. SIZE_T bytesRead;
  496. // Walk the exported functions in the target module.
  497. for (unsigned int i = 0; i < addr->ExportDirectory->NumberOfFunctions; ++i)
  498. {
  499. const WORD* const ordValue = (WORD*)((addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNameOrdinals) + (i * sizeof(WORD)));
  500. if (!NameLength)
  501. {
  502. bool found = false;
  503. // Compare ordinal values without magic bitoperations!
  504. if ((addr->ExportDirectory->Base + *ordValue) == *reinterpret_cast<WORD*>(&NameOrdinal))
  505. {
  506. funcAddrPtr = (DWORD*)((addr->BufferBaseAddress + addr->ExportDirectory->AddressOfFunctions) + (sizeof(DWORD) * *ordValue));
  507. found = true;
  508. }
  509. // Skip the entry if it is not found.
  510. if (!found || ((Byte*)funcAddrPtr < addr->BufferBaseAddress || (Byte*)funcAddrPtr > addr->BufferEndAddress))
  511. {
  512. continue;
  513. }
  514. if (*funcAddrPtr > addr->DirectoryAddress->VirtualAddress && *funcAddrPtr < (addr->DirectoryAddress->VirtualAddress + addr->DirectoryAddress->Size))
  515. {
  516. const Win32ModuleInformation* modBaseAddr = this->GetResolvedModule((char*)(addr->BufferBaseAddress + *funcAddrPtr), &ResurseDotIndex, NameOrdinal);
  517. // Sometimes infinite redirecting causes stack overflowing. Terminate this sequence by returning not found.
  518. if (!modBaseAddr || (SIZE_T)addr->BaseAddress == modBaseAddr->BaseAddress)
  519. {
  520. return EAT_ADDRESS_NOT_FOUND;
  521. }
  522. Byte dllBuffer[0x400];
  523. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  524. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  525. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  526. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  527. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  528. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  529. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  530. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  531. SIZE_T forwardedAddress = this->GetAddressFromExportTable(&addrStruct, (char*)addr->BufferBaseAddress + *funcAddrPtr + ResurseDotIndex + 2, NameLength);
  532. delete[] exportDirectoryBuffer;
  533. return forwardedAddress;
  534. }
  535. return (SIZE_T)(addr->BaseAddress + *funcAddrPtr);
  536. }
  537. else
  538. {
  539. const DWORD* const stringPtr = (DWORD*)((addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNames) + (i * sizeof(DWORD)));
  540. const char* const functionName = (char*)(addr->BufferBaseAddress + *stringPtr);
  541. if ((functionName > (char*)addr->BufferBaseAddress + addr->DirectoryAddress->VirtualAddress && (functionName + NameLength + 1) < (char*)addr->BufferEndAddress) && memcmp(NameOrdinal, functionName, NameLength) == 0)
  542. {
  543. funcAddrPtr = (DWORD*)((addr->BufferBaseAddress + addr->ExportDirectory->AddressOfFunctions) + (sizeof(DWORD) * *ordValue));
  544. if (*funcAddrPtr > addr->DirectoryAddress->VirtualAddress && *funcAddrPtr < (addr->DirectoryAddress->VirtualAddress + addr->DirectoryAddress->Size))
  545. {
  546. const Win32ModuleInformation* modBaseAddr = this->GetResolvedModule((char*)(addr->BufferBaseAddress + *funcAddrPtr), &ResurseDotIndex, NameOrdinal);
  547. if (!modBaseAddr || (SIZE_T)addr->BaseAddress == modBaseAddr->BaseAddress)
  548. {
  549. return EAT_ADDRESS_NOT_FOUND;
  550. }
  551. Byte dllBuffer[0x400];
  552. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  553. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  554. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  555. // Check if the size of the data directory is valid.
  556. if (dataDir.Size)
  557. {
  558. // Read the export directory from memory.
  559. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  560. b = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, &bytesRead);
  561. // Check whether it was read succesfully.
  562. if (b && bytesRead == dataDir.Size)
  563. {
  564. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  565. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  566. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  567. SIZE_T forwardedAddress = this->GetAddressFromExportTable(&addrStruct, (char*)(addr->BufferBaseAddress + *funcAddrPtr + ResurseDotIndex + 1), NameLength);
  568. delete[] exportDirectoryBuffer;
  569. return forwardedAddress;
  570. }
  571. else
  572. {
  573. return EAT_ADDRESS_NOT_FOUND;
  574. }
  575. }
  576. else
  577. {
  578. return EAT_ADDRESS_NOT_FOUND;
  579. }
  580. }
  581. return (SIZE_T)(addr->BaseAddress + *funcAddrPtr);
  582. }
  583. }
  584. }
  585. }
  586. return EAT_ADDRESS_NOT_FOUND;
  587. }
  588. // Attempts to retrieve function name associated to ordinal import from the export table of the loaded module.
  589. // Returns a pointer to the function name if it exists. If the function is not found, the return value is NULL.
  590. const char* PortableExecutable32::GetOrdinalFunctionNameFromExportTable(const AddrStruct* addr, const WORD ordinal) const
  591. {
  592. const WORD* const ordinals = (WORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNameOrdinals);
  593. for (unsigned int i = 0; i < addr->ExportDirectory->NumberOfFunctions; ++i)
  594. {
  595. if ((addr->ExportDirectory->Base + ordinals[i]) == ordinal)
  596. {
  597. const DWORD* const stringPtr = (DWORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNames + i * sizeof(DWORD));
  598. const Byte* const absStringPtr = (Byte*)(addr->BufferBaseAddress + *stringPtr);
  599. // Make sure the string points inside of the buffer. Scrambled EAT would crash the application.
  600. if (absStringPtr > (addr->BufferBaseAddress + addr->DirectoryAddress->Size) && absStringPtr < addr->BufferEndAddress)
  601. {
  602. return (const char*)absStringPtr;
  603. }
  604. }
  605. }
  606. return NULL;
  607. }
  608. // Retrieves the import table from the PE header of the loaded process. This information is stored in the global storage that has process lifetime.
  609. // Note that IMAGE_NT_HEADERS, IMAGE_OPTIONAL_HEADER, IMAGE_THUNK_DATA and SIZE_T are explicitly defined as the 32 bit version. If compiled as 64 bit the structs differ.
  610. const bool PortableExecutable32::GetImportAddressTable() const
  611. {
  612. // We use a return value to indicate whether function names can actually be retrieved using OriginalFirstThunk.
  613. bool result = true;
  614. // Read process memory into local buffer in order to load IAT.
  615. Byte moduleBuffer[0x400];
  616. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, 0x400, NULL);
  617. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(moduleBuffer + ((IMAGE_DOS_HEADER*)moduleBuffer)->e_lfanew);
  618. // The PE Headers are not valid, the pointer runs outside the bounds of the buffer.
  619. if ((Byte*)pNTHeader > (moduleBuffer + 0x400))
  620. {
  621. return false;
  622. }
  623. const IMAGE_OPTIONAL_HEADER32* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader;
  624. // Read the import descriptor table into local memory.
  625. unsigned int counter = 0;
  626. IMAGE_IMPORT_DESCRIPTOR pDesc;
  627. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (counter * sizeof(IMAGE_IMPORT_DESCRIPTOR))), &pDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR), NULL);
  628. // Check whether OriginalFirstThunk is non-zero. If it is zero, the target process executable may be packed. We can find
  629. // the function addresses, but we cannot find the function names directly.
  630. if (!pDesc.OriginalFirstThunk)
  631. {
  632. result = false;
  633. }
  634. while (pDesc.FirstThunk && pDesc.Name != 0xFFFF)
  635. {
  636. // Read DLL name from import descriptor entry.
  637. char dllName[48];
  638. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(pDesc.Name + this->mBaseAddress), dllName, 48, NULL);
  639. // Add new import descriptor to the table.
  640. ImportTableDescriptor& impDesc = LoadedProcessPEInformation.ImportAddressTable.Add();
  641. impDesc.ModuleName = dllName;
  642. // Get base address and length of desired DLL, and look up the function foreign name in the export table of that DLL.
  643. WString apiSetDllName = ToLower(dllName);
  644. const Win32ModuleInformation* modBaseAddr = NULL;
  645. // Check whether we have to deal with an ApiSet redirection or not.
  646. if (apiSetDllName.StartsWith("api-ms-win") || apiSetDllName.StartsWith("ext-ms-win"))
  647. {
  648. // Windows ApiSetSchema redirection detected. Remove the file extension before resolving.
  649. const int lastDot = apiSetDllName.ReverseFind('.');
  650. if (lastDot != -1)
  651. {
  652. apiSetDllName.Remove(lastDot, apiSetDllName.GetLength() - lastDot);
  653. }
  654. // Recursively resolve the redirection.
  655. while (!modBaseAddr)
  656. {
  657. // First remove the prefix, the resolving works without the prefix.
  658. apiSetDllName.Remove(0, 4);
  659. // Resolve the redirection.
  660. const wchar* const outWString = this->InlineResolveApiSetSchema(apiSetDllName);
  661. if (outWString)
  662. {
  663. apiSetDllName = outWString;
  664. delete[] outWString;
  665. // Get the module base address from the internal module list, and set the logical base address.
  666. modBaseAddr = mModuleManager->FindModule(apiSetDllName.ToString());
  667. impDesc.LogicalBaseAddress = modBaseAddr ? modBaseAddr->BaseAddress : 0;
  668. }
  669. }
  670. }
  671. else
  672. {
  673. // Get the module base address from the internal module list.
  674. modBaseAddr = mModuleManager->FindModule(apiSetDllName.ToString());
  675. impDesc.LogicalBaseAddress = 0;
  676. }
  677. // Does the module have a base address? If so, we parse its export table.
  678. if (modBaseAddr)
  679. {
  680. impDesc.ModulePointer = modBaseAddr;
  681. Byte dllBuffer[0x400];
  682. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  683. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  684. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  685. // Check whether the discovered module actually has an export table.
  686. if (dataDir.Size)
  687. {
  688. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  689. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  690. Byte* const bufBase = (exportDirectoryBuffer - dataDir.VirtualAddress);
  691. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  692. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  693. IMAGE_THUNK_DATA32 thunk;
  694. unsigned int count = 0;
  695. do
  696. {
  697. // Try to read current thunk into local memory.
  698. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pDesc.OriginalFirstThunk + count * sizeof(DWORD)), &thunk, sizeof(IMAGE_THUNK_DATA32), NULL);
  699. ImportAddressTableEntry funcEntry;
  700. // Check for 32-bit ordinal magic flag.
  701. if (thunk.u1.Ordinal & IMAGE_ORDINAL_FLAG32)
  702. {
  703. funcEntry.Ordinal = IMAGE_ORDINAL32(thunk.u1.Ordinal);
  704. funcEntry.Hint = 0;
  705. if (addrStruct.ExportDirectory->AddressOfNames)
  706. {
  707. funcEntry.FunctionName = this->GetOrdinalFunctionNameFromExportTable(&addrStruct, funcEntry.Ordinal);
  708. }
  709. }
  710. else
  711. {
  712. // Read function name from thunk data.
  713. char funcName[96];
  714. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + thunk.u1.AddressOfData), funcName, 96, NULL);
  715. // Set ordinal value to 0, read function name and WORD sized hint from the first two read bytes sequence.
  716. funcEntry.Ordinal = 0;
  717. funcEntry.Hint = *(WORD*)funcName;
  718. funcEntry.FunctionName = funcName + sizeof(WORD);
  719. }
  720. // In a rare occasion the ordinal bit-flag is already removed. In this case the ordinal should be detected by section awareness.
  721. if (funcEntry.FunctionName.IsEmpty() && !RVAPointsInsideSection(thunk.u1.Ordinal))
  722. {
  723. funcEntry.Ordinal = (WORD)thunk.u1.Ordinal;
  724. funcEntry.Hint = 0;
  725. if (addrStruct.ExportDirectory->AddressOfNames)
  726. {
  727. funcEntry.FunctionName = this->GetOrdinalFunctionNameFromExportTable(&addrStruct, funcEntry.Ordinal);
  728. }
  729. }
  730. // If the function name is empty even after ordinal resolving, the function has no name. Give it an automated name.
  731. if (funcEntry.FunctionName.IsEmpty())
  732. {
  733. String localModName = dllName;
  734. const int dotIndex = localModName.ReverseFind('.');
  735. localModName.Remove(dotIndex, localModName.GetLength() - dotIndex);
  736. funcEntry.FunctionName = Format("%s.%i", localModName, funcEntry.Ordinal);
  737. }
  738. // Save the thunk address of the function.
  739. funcEntry.ThunkAddress = this->mBaseAddress + pDesc.FirstThunk + count++ * sizeof(DWORD);
  740. // Read function address from thunk data and increment function iteration counter.
  741. DWORD funcAddress;
  742. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)funcEntry.ThunkAddress, &funcAddress, sizeof(DWORD), NULL);
  743. if (!funcAddress)
  744. {
  745. continue;
  746. }
  747. funcEntry.VirtualAddress = funcAddress;
  748. funcEntry.Flag = 0;
  749. // Check whether actual address is equal to the address it should be, otherwise the IAT is hooked.
  750. const SIZE_T eatAddress = this->GetAddressFromExportTable(&addrStruct, funcEntry.Ordinal ? (char*)funcEntry.Ordinal : funcEntry.FunctionName.Begin(), funcEntry.Ordinal ? 0 : funcEntry.FunctionName.GetLength());
  751. if (eatAddress == EAT_ADDRESS_NOT_FOUND)
  752. {
  753. funcEntry.Flag = IAT_FLAG_NOT_FOUND;
  754. }
  755. else if (eatAddress != funcEntry.VirtualAddress)
  756. {
  757. funcEntry.Flag = IAT_FLAG_HOOKED;
  758. }
  759. // Add function to import descriptor.
  760. impDesc.FunctionList.Add(funcEntry);
  761. }
  762. while (thunk.u1.AddressOfData);
  763. delete[] exportDirectoryBuffer;
  764. }
  765. }
  766. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (++counter * sizeof(IMAGE_IMPORT_DESCRIPTOR))), &pDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR), NULL);
  767. }
  768. return result;
  769. }
  770. // Places a hook in the IAT, replacing the function address with another one.
  771. // First parameter is either a pointer to a buffer containing the function name or an ordinal value.
  772. bool PortableExecutable32::PlaceIATHook(const Win32ModuleInformation* modBase, const char* NameOrdinal, const SIZE_T newAddress, bool IsOrdinal) const
  773. {
  774. bool result = false;
  775. Byte* const moduleBuffer = new Byte[modBase->Length];
  776. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, modBase->Length, NULL);
  777. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(moduleBuffer + ((IMAGE_DOS_HEADER*)moduleBuffer)->e_lfanew);
  778. const IMAGE_OPTIONAL_HEADER32* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader;
  779. const IMAGE_IMPORT_DESCRIPTOR* pDesc = (IMAGE_IMPORT_DESCRIPTOR*)(moduleBuffer + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  780. // Additional sanity checking, to avoid pDesc to be located outside of the allocated buffer.
  781. if ((Byte*)pDesc > moduleBuffer && (Byte*)pDesc < moduleBuffer + modBase->Length)
  782. {
  783. while (pDesc->FirstThunk)
  784. {
  785. const char* dllName = (char*)(moduleBuffer + pDesc->Name);
  786. IMAGE_THUNK_DATA32* thunk;
  787. unsigned int count = 0;
  788. do
  789. {
  790. thunk = (IMAGE_THUNK_DATA32*)(moduleBuffer + pDesc->OriginalFirstThunk + count * sizeof(DWORD));
  791. void* const AddressAddr = (void*)(this->mBaseAddress + pDesc->FirstThunk + count++ * sizeof(DWORD));
  792. if (IsOrdinal)
  793. {
  794. if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
  795. {
  796. // Ordinal import detected, check whether ordinal matches input value.
  797. if (IMAGE_ORDINAL32(thunk->u1.Ordinal) == (SIZE_T)NameOrdinal)
  798. {
  799. DWORD dwOldProtect;
  800. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
  801. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, AddressAddr, &newAddress, sizeof(DWORD), NULL);
  802. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(DWORD), dwOldProtect, &dwOldProtect);
  803. result = true;
  804. break;
  805. }
  806. }
  807. }
  808. else
  809. {
  810. // Check if function is ordinal, because if it is, skip this one.
  811. if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
  812. {
  813. continue;
  814. }
  815. const char* funcName = (char*)(moduleBuffer + thunk->u1.AddressOfData + sizeof(WORD));
  816. // Named import detected, check whether import matches input name.
  817. if (strcmp(funcName, NameOrdinal) == 0)
  818. {
  819. DWORD dwOldProtect;
  820. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
  821. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, AddressAddr, &newAddress, sizeof(DWORD), NULL);
  822. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(DWORD), dwOldProtect, &dwOldProtect);
  823. result = true;
  824. break;
  825. }
  826. }
  827. }
  828. while (thunk->u1.AddressOfData);
  829. ++pDesc;
  830. }
  831. }
  832. // Success, free used buffers and return.
  833. delete[] moduleBuffer;
  834. return result;
  835. }
  836. // Attempts to restore the PE headers from a file on the harddisk to a module loaded in memory.
  837. // Retuns true if the operation succeeded and false if it did not succeed.
  838. bool PortableExecutable32::RestorePEHeaderFromFile(const String& fileName, const Win32ModuleInformation& module) const
  839. {
  840. bool result = true;
  841. // Create handle to file on the disk.
  842. HANDLE hFile = CreateFile(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  843. if (!hFile || hFile == INVALID_HANDLE_VALUE)
  844. {
  845. result = false;
  846. }
  847. // Get file size and read file into buffer.
  848. LARGE_INTEGER size;
  849. GetFileSizeEx(hFile, &size);
  850. DWORD bytesRead;
  851. Byte* const fileBuffer = new Byte[size.LowPart];
  852. if (!ReadFile(hFile, fileBuffer, size.LowPart, &bytesRead, NULL))
  853. {
  854. result = false;
  855. }
  856. // Read header size.
  857. const IMAGE_DOS_HEADER* const pDOSHeader = (IMAGE_DOS_HEADER*)fileBuffer;
  858. if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
  859. {
  860. return false;
  861. }
  862. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
  863. if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
  864. {
  865. result = false;
  866. }
  867. const IMAGE_OPTIONAL_HEADER32* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader;
  868. // Write header data into process memory at designated location.
  869. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, pOptionalHeader->SizeOfHeaders, PAGE_READWRITE, &bytesRead);
  870. if (!CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, fileBuffer, pOptionalHeader->SizeOfHeaders, NULL))
  871. {
  872. result = false;
  873. }
  874. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, pOptionalHeader->SizeOfHeaders, bytesRead, &bytesRead);
  875. delete[] fileBuffer;
  876. CloseHandle(hFile);
  877. return result;
  878. }
  879. // Attempts to hide a module from the loaded process. Hiding means it not being visible for debuggers anymore.
  880. // Returns true if the operation succeeded, and false if it did not succeed.
  881. bool PortableExecutable32::HideModuleFromProcess(const Win32ModuleInformation& module) const
  882. {
  883. if (!CrySearchRoutines.NtQueryInformationProcess)
  884. {
  885. return false;
  886. }
  887. // Retrieve target process information using Nt function.
  888. #ifdef _WIN64
  889. ULONG_PTR pebAddr;
  890. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessWow64Information, &pebAddr, sizeof(ULONG_PTR), NULL) != STATUS_SUCCESS)
  891. #else
  892. PROCESS_BASIC_INFORMATION procBlock;
  893. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessBasicInformation, &procBlock, sizeof(PROCESS_BASIC_INFORMATION), NULL) != STATUS_SUCCESS)
  894. #endif
  895. {
  896. return false;
  897. }
  898. PEB_LDR_DATA32 peb;
  899. SIZE_T pebPtr;
  900. // Read process environment block and loader data from the process memory.
  901. #ifdef _WIN64
  902. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (unsigned char*)pebAddr + offsetof(PEB32, LoaderData), &pebPtr, sizeof(DWORD), NULL);
  903. #else
  904. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (unsigned char*)procBlock.PebBaseAddress + offsetof(PEB, LoaderData), &pebPtr, sizeof(DWORD), NULL);
  905. #endif
  906. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)pebPtr, &peb, sizeof(PEB_LDR_DATA), NULL);
  907. LDR_MODULE32 curModule;
  908. bool found = false;
  909. unsigned int retryCount = 0;
  910. int moduleCount = 0;
  911. SIZE_T Head = peb.InMemoryOrderModuleList.Flink;
  912. SIZE_T Node = Head;
  913. do
  914. {
  915. // Read current linked list module from the process memory.
  916. if (CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(Node -= sizeof(LIST_ENTRY32)), &curModule, sizeof(LDR_MODULE32), NULL))
  917. {
  918. if (curModule.BaseAddress)
  919. {
  920. // some applications cause an infinite loop. This is one way to help preventing it.
  921. ++moduleCount;
  922. // A valid module is found, read its base dll name from the process memory.
  923. wchar BaseDllName[MAX_PATH];
  924. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)curModule.BaseDllName.Buffer, BaseDllName, curModule.BaseDllName.Length, NULL);
  925. BaseDllName[curModule.BaseDllName.Length / 2] = 0;
  926. PathStripPathW(BaseDllName);
  927. // Compare current module's base name and desired module name, if it matches, the desired one is found.
  928. String selModName = mModuleManager->GetModuleFilename(module.BaseAddress);
  929. if (memcmp(selModName.ToWString().Begin(), BaseDllName, selModName.GetLength() * sizeof(wchar)) == 0)
  930. {
  931. found = true;
  932. for (unsigned int index = 0; index < 3; (Node += sizeof(LIST_ENTRY32)), index++)
  933. {
  934. LIST_ENTRY32 current;
  935. // Read current, previous and next list entry from the process memory.
  936. BOOL localRes = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)Node, &current, sizeof(LIST_ENTRY32), NULL);
  937. if (!localRes)
  938. {
  939. found = false;
  940. break;
  941. }
  942. const SIZE_T nextItemAddr = current.Flink;
  943. const SIZE_T prevItemAddr = current.Blink;
  944. // Overwrite the pointers of the previous and next list entry so the current one is effectively hidden.
  945. localRes = CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, (void*)current.Blink, &nextItemAddr, sizeof(DWORD), NULL);
  946. localRes = CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, (unsigned char*)current.Flink + sizeof(DWORD), &prevItemAddr, sizeof(DWORD), NULL);
  947. }
  948. break;
  949. }
  950. }
  951. }
  952. else
  953. {
  954. // Prevent infinite while looping. In most situations this code may be unnessecary.
  955. if (++retryCount == 3)
  956. {
  957. break;
  958. }
  959. }
  960. // Desired module was not yet found, traverse to the next one.
  961. Node = curModule.InMemoryOrderModuleList.Flink;
  962. }
  963. while(Head != Node && moduleCount < mModuleManager->GetModuleCount());
  964. return found;
  965. }
  966. // Dumps a specific section in the loaded process to a file on the harddisk.
  967. // Returns true if the operation succeeded, and false if it did not succeed.
  968. bool PortableExecutable32::DumpProcessSection(const String& fileName, const SIZE_T address, const SIZE_T size) const
  969. {
  970. bool result = true;
  971. Byte* const buffer = new Byte[size];
  972. SIZE_T bytesRead;
  973. // Read section memory from target process and save it into the buffer.
  974. if (!CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)address, buffer, size, &bytesRead)
  975. && bytesRead == 0)
  976. {
  977. delete[] buffer;
  978. return false;
  979. }
  980. // Create dmp file on the disk.
  981. HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  982. if (hFile == INVALID_HANDLE_VALUE)
  983. {
  984. result = false;
  985. }
  986. // Write the data read to the file.
  987. DWORD bytesWritten;
  988. #ifdef _WIN64
  989. if (!WriteFile(hFile, buffer, (DWORD)bytesRead, &bytesWritten, NULL))
  990. #else
  991. if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL))
  992. #endif
  993. {
  994. DeleteFile(fileName);
  995. result = false;
  996. }
  997. // All succeeded, free resources and return.
  998. CloseHandle(hFile);
  999. delete[] buffer;
  1000. return result;
  1001. }
  1002. // Attempts to load a dynamic link library into the target process.
  1003. // Returns true if the operation succeeded, and false if it did not succeed.
  1004. bool PortableExecutable32::LoadLibraryExternal(const String& library) const
  1005. {
  1006. // Allocate memory space for the library path.
  1007. void* const lpRemoteAddress = VirtualAllocEx(this->mProcessHandle, NULL, library.GetLength(), MEM_COMMIT, PAGE_READWRITE);
  1008. SIZE_T bytesWritten;
  1009. // Write path to library into the newly allocated memory.
  1010. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpRemoteAddress, library, library.GetLength(), &bytesWritten);
  1011. if (bytesWritten != library.GetLength())
  1012. {
  1013. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1014. return false;
  1015. }
  1016. // Create a thread remotely that executes LoadLibraryA, pointing to the allocated string as parameter.
  1017. #ifndef _WIN64
  1018. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"), lpRemoteAddress, NULL, NULL);
  1019. #else
  1020. DWORD krnl32Base;
  1021. const int modCount = mModuleManager->GetModuleCount();
  1022. for (int i = 0; i < modCount; ++i)
  1023. {
  1024. if (ToLower(mModuleManager->GetModuleFilename((*mModuleManager)[i].BaseAddress)) == "kernel32.dll")
  1025. {
  1026. krnl32Base = (DWORD)(*mModuleManager)[i].BaseAddress;
  1027. break;
  1028. }
  1029. }
  1030. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)Wow64GetProcAddress(this->mProcessHandle, krnl32Base, "LoadLibraryA"), lpRemoteAddress, NULL, NULL);
  1031. #endif
  1032. // Succesfully created thread, wait for it to complete and free resources after.
  1033. if (hThread && hThread != INVALID_HANDLE_VALUE)
  1034. {
  1035. WaitForSingleObject(hThread, 5000);
  1036. CloseHandle(hThread);
  1037. }
  1038. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1039. return !!hThread;
  1040. }
  1041. // Attempts to load a dynamic link library into the target process.
  1042. // Returns true if the operation succeeded, and false if it did not succeed.
  1043. bool PortableExecutable32::LoadLibraryExternalHijack(const String& library, HANDLE hThread) const
  1044. {
  1045. // If the thread wasn't opened succesfully, the function can return inmediately.
  1046. if (!hThread || hThread == INVALID_HANDLE_VALUE)
  1047. {
  1048. return false;
  1049. }
  1050. // Allocate memory space for the library path.
  1051. void* const lpRemoteAddress = VirtualAllocEx(this->mProcessHandle, NULL, library.GetLength(), MEM_COMMIT, PAGE_READWRITE);
  1052. SIZE_T bytesWritten;
  1053. // Write path to library into the newly allocated memory.
  1054. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpRemoteAddress, library, library.GetLength(), &bytesWritten);
  1055. if (bytesWritten != library.GetLength())
  1056. {
  1057. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1058. return false;
  1059. }
  1060. // The shellcode that is written and executed inside the target program:
  1061. // push 0xCCCCCCCC
  1062. // pushad
  1063. // pushfd
  1064. // mov ebx, 0xCCCCCCCC
  1065. // push 0xCCCCCCCC
  1066. // call ebx
  1067. // popfd
  1068. // popad
  1069. // mov dword ptr [0xCCCCCCCC], 0x1337
  1070. // ret
  1071. Byte shellCode[] = { 0x68, 0xCC, 0xCC, 0xCC, 0xCC, 0x60, 0x9C, 0xBB, 0xCC, 0xCC, 0xCC, 0xCC, 0x68, 0xCC, 0xCC, 0xCC, 0xCC, 0xFF, 0xD3, 0x9D, 0x61, 0xC7, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, 0x37, 0x13, 0x00, 0x00, 0xC3 };
  1072. // Allocate executable block of memory for the shellcode.
  1073. void* const lpShellCode = VirtualAllocEx(this->mProcessHandle, NULL, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  1074. const DWORD flagAddress = (DWORD)lpShellCode + 0x100;
  1075. // Suspend the thread and back up the context.
  1076. #ifdef _WIN64
  1077. Wow64SuspendThread(hThread);
  1078. WOW64_CONTEXT ctx;
  1079. ctx.ContextFlags = WOW64_CONTEXT_FULL;
  1080. Wow64GetThreadContext(hThread, &ctx);
  1081. #else
  1082. SuspendThread(hThread);
  1083. CONTEXT ctx;
  1084. ctx.ContextFlags = CONTEXT_FULL;
  1085. GetThreadContext(hThread, &ctx);
  1086. #endif
  1087. // Replace addresses with correct ones at runtime.
  1088. *(DWORD*)&shellCode[1] = ctx.Eip;
  1089. #ifdef _WIN64
  1090. const Win32ModuleInformation* krnl32mod = mModuleManager->FindModule("kernel32.dll");
  1091. if (!krnl32mod)
  1092. {
  1093. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1094. CloseHandle(hThread);
  1095. return false;
  1096. }
  1097. *(DWORD*)&shellCode[8] = Wow64GetProcAddress(this->mProcessHandle, (DWORD)krnl32mod->BaseAddress, "LoadLibraryA");
  1098. #else
  1099. *(DWORD*)&shellCode[8] = (DWORD)LoadLibraryA;
  1100. #endif
  1101. *(DWORD*)&shellCode[13] = (DWORD)lpRemoteAddress;
  1102. *(DWORD*)&shellCode[23] = flagAddress;
  1103. // Write the shellcode to the remotely allocated buffer.
  1104. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpShellCode, shellCode, sizeof(shellCode), &bytesWritten);
  1105. if (bytesWritten != sizeof(shellCode))
  1106. {
  1107. VirtualFreeEx(this->mProcessHandle, lpShellCode, 0, MEM_RELEASE);
  1108. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1109. return false;
  1110. }
  1111. // Change EIP to resume execution at the shellcode.
  1112. ctx.Eip = (DWORD)lpShellCode;
  1113. // Place the new context inside the thread.
  1114. #ifdef _WIN64
  1115. Wow64SetThreadContext(hThread, &ctx);
  1116. #else
  1117. SetThreadContext(hThread, &ctx);
  1118. #endif
  1119. // Flush the instruction cache to avoid problems with cached instructions.
  1120. FlushInstructionCache(this->mProcessHandle, lpShellCode, sizeof(shellCode));
  1121. // Resume the thread to let the DLL load and close thread handle.
  1122. ResumeThread(hThread);
  1123. // Sample the completion flag to contain the magic number 0x1337. Block the thread until the sampling is succesful.
  1124. DWORD magic = 0;
  1125. unsigned int threshold = 0;
  1126. do
  1127. {
  1128. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)flagAddress, &magic, sizeof(DWORD), &bytesWritten);
  1129. // Prevent CrySearch to start eating CPU time while still trying to have an accurate sample.
  1130. Sleep(75);
  1131. ++threshold;
  1132. }
  1133. while (magic != 0x1337 && threshold < THREAD_HIJACK_MAGIC_PROBE_THRESHOLD);
  1134. // The loop finished, free memory pages and close thread handle.
  1135. VirtualFreeEx(this->mProcessHandle, lpShellCode, 0, MEM_RELEASE);
  1136. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1137. CloseHandle(hThread);
  1138. return (threshold != THREAD_HIJACK_MAGIC_PROBE_THRESHOLD);
  1139. }
  1140. // Attempts to unload a loaded module from the target process.
  1141. void PortableExecutable32::UnloadLibraryExternal(const SIZE_T module) const
  1142. {
  1143. #ifndef _WIN64
  1144. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibrary"), (void*)module, NULL, NULL);
  1145. #else
  1146. DWORD krnl32Base;
  1147. const int modCount = mModuleManager->GetModuleCount();
  1148. for (int i = 0; i < modCount; ++i)
  1149. {
  1150. if (ToLower(mModuleManager->GetModuleFilename((*mModuleManager)[i].BaseAddress)) == "kernel32.dll")
  1151. {
  1152. krnl32Base = (DWORD)(*mModuleManager)[i].BaseAddress;
  1153. break;
  1154. }
  1155. }
  1156. DWORD freeAddr = Wow64GetProcAddress(this->mProcessHandle, krnl32Base, "FreeLibrary");
  1157. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)freeAddr, (void*)module, NULL, NULL);
  1158. #endif
  1159. // Succesfully created thread, wait for it to complete and free resources after.
  1160. if (hThread && hThread != INVALID_HANDLE_VALUE)
  1161. {
  1162. WaitForSingleObject(hThread, 5000);
  1163. CloseHandle(hThread);
  1164. }
  1165. }
  1166. // Restores the original address of an imported function from the export table.
  1167. void PortableExecutable32::RestoreExportTableAddressImport(const Win32ModuleInformation* modBase, const SIZE_T baseAddress, const char* NameOrdinal, const int NameLength) const
  1168. {
  1169. Byte dllBuffer[0x400];
  1170. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)baseAddress, dllBuffer, 0x400, NULL);
  1171. const IMAGE_NT_HEADERS32* const pNTHeader =(IMAGE_NT_HEADERS32*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  1172. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER32*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  1173. // Check whether the discovered module actually has an export table.
  1174. if (dataDir.Size)
  1175. {
  1176. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  1177. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(baseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  1178. Byte* const bufBase = (exportDirectoryBuffer - dataDir.VirtualAddress);
  1179. AddrStruct addrStruct((Byte*)baseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  1180. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  1181. this->PlaceIATHook(modBase, NameOrdinal, this->GetAddressFromExportTable(&addrStruct, NameOrdinal, NameLength), !NameLength);
  1182. delete[] exportDirectoryBuffer;
  1183. }
  1184. }
  1185. // -------------------------------------------------------------------------------------------------------------------------------
  1186. // PE 64 methods
  1187. // -------------------------------------------------------------------------------------------------------------------------------
  1188. #ifdef _WIN64
  1189. PortableExecutable64::~PortableExecutable64()
  1190. {
  1191. }
  1192. // Retrieves PE header information from the loaded process. Information is saved in global storage that has process lifetime.
  1193. // Note that IMAGE_NT_HEADERS and IMAGE_OPTIONAL_HEADER are explicitly defined as the 32 bit version. If compiled as 64 bit the structs differ.
  1194. void PortableExecutable64::GetExecutablePeInformation() const
  1195. {
  1196. // Clear image sections before getting new ones.
  1197. LoadedProcessPEInformation.Reset();
  1198. // Read process memory into local buffer in order to load PE headers.
  1199. Byte moduleBuffer[0x400];
  1200. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, 0x400, NULL);
  1201. // Load PE headers.
  1202. const IMAGE_NT_HEADERS64* const pNTHeader =(IMAGE_NT_HEADERS64*)(moduleBuffer + ((IMAGE_DOS_HEADER*)moduleBuffer)->e_lfanew);
  1203. // When the PE Headers are destroyed at runtime the pointer to the headers may run out of the buffer's bounds.
  1204. if ((Byte*)pNTHeader > (moduleBuffer + 0x400))
  1205. {
  1206. LoadedProcessPEInformation.PEFields.Clear();
  1207. return;
  1208. }
  1209. const IMAGE_OPTIONAL_HEADER64* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER64*)&pNTHeader->OptionalHeader;
  1210. const IMAGE_FILE_HEADER* const pFileHeader = &(pNTHeader->FileHeader);
  1211. // Retrieve the type of machine the PE executable can run on.
  1212. this->ParseMachineType(pFileHeader->Machine);
  1213. // Retrieve PE fields and add them to the map.
  1214. LoadedProcessPEInformation.PEFields.Add("Number of sections", pFileHeader->NumberOfSections);
  1215. LoadedProcessPEInformation.PEFields.Add("Size of optional header", Format("%X", pFileHeader->SizeOfOptionalHeader));
  1216. LoadedProcessPEInformation.PEFields.Add("Pointer to symbol table", (int)pFileHeader->PointerToSymbolTable);
  1217. LoadedProcessPEInformation.PEFields.Add("Number of symbols", (int)pFileHeader->NumberOfSymbols);
  1218. LoadedProcessPEInformation.PEFields.Add("Image base", Format("%llX", (__int64)pOptionalHeader->ImageBase));
  1219. LoadedProcessPEInformation.PEFields.Add("Base of code", Format("%llX", (__int64)pOptionalHeader->BaseOfCode));
  1220. LoadedProcessPEInformation.PEFields.Add("Address of entrypoint", Format("%llX", (__int64)pOptionalHeader->AddressOfEntryPoint));
  1221. LoadedProcessPEInformation.PEFields.Add("Size of code", Format("%llX", (__int64)pOptionalHeader->SizeOfCode));
  1222. LoadedProcessPEInformation.PEFields.Add("Size of initialized data", Format("%llX", (__int64)pOptionalHeader->SizeOfInitializedData));
  1223. LoadedProcessPEInformation.PEFields.Add("Size of uninitialized data", Format("%llX", (__int64)pOptionalHeader->SizeOfUninitializedData));
  1224. LoadedProcessPEInformation.PEFields.Add("Section alignment", Format("%llX", (__int64)pOptionalHeader->SectionAlignment));
  1225. LoadedProcessPEInformation.PEFields.Add("File alignment", Format("%llX", (__int64)pOptionalHeader->FileAlignment));
  1226. LoadedProcessPEInformation.PEFields.Add("Size of image", Format("%llX", (__int64)pOptionalHeader->SizeOfImage));
  1227. LoadedProcessPEInformation.PEFields.Add("Size of headers", Format("%llX", (__int64)pOptionalHeader->SizeOfHeaders));
  1228. LoadedProcessPEInformation.PEFields.Add("Checksum", Format("%llX", (__int64)pOptionalHeader->CheckSum));
  1229. LoadedProcessPEInformation.PEFields.Add("Linker version", Format("%i.%i", pOptionalHeader->MajorLinkerVersion, pOptionalHeader->MinorLinkerVersion));
  1230. LoadedProcessPEInformation.PEFields.Add("OS version", Format("%i.%i", pOptionalHeader->MajorOperatingSystemVersion, pOptionalHeader->MinorOperatingSystemVersion));
  1231. LoadedProcessPEInformation.PEFields.Add("Image version", Format("%i.%i", pOptionalHeader->MajorImageVersion, pOptionalHeader->MinorImageVersion));
  1232. LoadedProcessPEInformation.PEFields.Add("Subsystem version", Format("%i.%i", pOptionalHeader->MajorSubsystemVersion, pOptionalHeader->MinorSubsystemVersion));
  1233. LoadedProcessPEInformation.PEFields.Add("Number of data directories", Format("%llX", (__int64)pOptionalHeader->NumberOfRvaAndSizes));
  1234. // Parse the last general property value of the PE header, save the section values and destroy the buffer.
  1235. this->ParseSubsystemValue(pOptionalHeader->Subsystem);
  1236. const DWORD sectionCount = pNTHeader->FileHeader.NumberOfSections;
  1237. const DWORD sectionSizeBytes = sizeof(IMAGE_SECTION_HEADER) * sectionCount;
  1238. const IMAGE_SECTION_HEADER* const firstSectionPtr = (IMAGE_SECTION_HEADER*)(this->mBaseAddress + ((Byte*)IMAGE_FIRST_SECTION(pNTHeader) - moduleBuffer));
  1239. // Get the COM header from the PE file.
  1240. this->GetDotNetDirectoryInformation(&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]);
  1241. // Retrieve the sections from the PE header.
  1242. Byte* const sectionBuffer = new Byte[sectionSizeBytes];
  1243. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, firstSectionPtr, sectionBuffer, sectionSizeBytes, NULL);
  1244. this->GetImageSectionsList((IMAGE_SECTION_HEADER*)sectionBuffer, sectionCount, LoadedProcessPEInformation.ImageSections);
  1245. delete[] sectionBuffer;
  1246. }
  1247. // Retrieves the address of a function in the export table of a module. Address can be returned for function by name or ordinal.
  1248. // Returns the address of the function, created from the module base address added by the function RVA.
  1249. // If the function is not found, the return value is 0xFFFFFFFF.
  1250. // The NameLength parameter contains the length of the name if there is a name, or 0 if the function is ordinal-based.
  1251. SIZE_T PortableExecutable64::GetAddressFromExportTable(const AddrStruct* addr, const char* NameOrdinal, const unsigned int NameLength) const
  1252. {
  1253. if (addr->ExportDirectory->AddressOfNameOrdinals)
  1254. {
  1255. const DWORD* funcAddrPtr = NULL;
  1256. int RecurseDotIndex = 0;
  1257. bool b;
  1258. SIZE_T bytesRead;
  1259. for (unsigned int i = 0; i < addr->ExportDirectory->NumberOfFunctions; ++i)
  1260. {
  1261. const WORD* const ordValue = (WORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNameOrdinals + (i * sizeof(WORD)));
  1262. if (!NameLength)
  1263. {
  1264. bool found = false;
  1265. // Compare ordinal values without magic bitoperations!
  1266. if ((addr->ExportDirectory->Base + *ordValue) == *reinterpret_cast<WORD*>(&NameOrdinal))
  1267. {
  1268. funcAddrPtr = (DWORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfFunctions + (sizeof(DWORD) * *ordValue));
  1269. found = true;
  1270. }
  1271. // Skip the entry if it is not found.
  1272. if (!found || ((Byte*)funcAddrPtr < addr->BufferBaseAddress || (Byte*)funcAddrPtr > addr->BufferEndAddress))
  1273. {
  1274. continue;
  1275. }
  1276. if (*funcAddrPtr > addr->DirectoryAddress->VirtualAddress && *funcAddrPtr < addr->DirectoryAddress->VirtualAddress + addr->DirectoryAddress->Size)
  1277. {
  1278. const Win32ModuleInformation* modBaseAddr = this->GetResolvedModule((char*)(addr->BufferBaseAddress + *funcAddrPtr), &RecurseDotIndex, NameOrdinal);
  1279. if (!modBaseAddr || (SIZE_T)addr->BaseAddress == modBaseAddr->BaseAddress)
  1280. {
  1281. return EAT_ADDRESS_NOT_FOUND;
  1282. }
  1283. Byte dllBuffer[0x400];
  1284. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  1285. const IMAGE_NT_HEADERS64* pNTHeader =(IMAGE_NT_HEADERS64*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  1286. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER64*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  1287. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  1288. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  1289. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  1290. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  1291. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  1292. const SIZE_T forwardedAddress = this->GetAddressFromExportTable(&addrStruct, (char*)addr->BufferBaseAddress + *funcAddrPtr + RecurseDotIndex + 1, true);
  1293. delete[] exportDirectoryBuffer;
  1294. return forwardedAddress;
  1295. }
  1296. return (SIZE_T)(addr->BaseAddress + *funcAddrPtr);
  1297. }
  1298. else
  1299. {
  1300. const DWORD* const stringPtr = (DWORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNames + (i * sizeof(DWORD)));
  1301. const char* const functionName = (char*)(addr->BufferBaseAddress + *stringPtr);
  1302. if ((functionName > (char*)addr->BufferBaseAddress + addr->DirectoryAddress->VirtualAddress && (functionName + NameLength + 1) < (char*)addr->BufferEndAddress) && memcmp(NameOrdinal, functionName, NameLength) == 0)
  1303. {
  1304. funcAddrPtr = (DWORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfFunctions + (sizeof(DWORD) * *ordValue));
  1305. if (*funcAddrPtr > addr->DirectoryAddress->VirtualAddress && *funcAddrPtr < addr->DirectoryAddress->VirtualAddress + addr->DirectoryAddress->Size)
  1306. {
  1307. const Win32ModuleInformation* modBaseAddr = this->GetResolvedModule((char*)(addr->BufferBaseAddress + *funcAddrPtr), &RecurseDotIndex, NameOrdinal);
  1308. if (!modBaseAddr || (SIZE_T)addr->BaseAddress == modBaseAddr->BaseAddress)
  1309. {
  1310. return EAT_ADDRESS_NOT_FOUND;
  1311. }
  1312. Byte dllBuffer[0x400];
  1313. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  1314. const IMAGE_NT_HEADERS64* const pNTHeader =(IMAGE_NT_HEADERS64*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  1315. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER64*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  1316. // Check if the size of the data directory is valid.
  1317. if (dataDir.Size)
  1318. {
  1319. // Read the export directory from memory.
  1320. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  1321. b = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, &bytesRead);
  1322. // Check whether it was read succesfully.
  1323. if (b && bytesRead == dataDir.Size)
  1324. {
  1325. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  1326. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  1327. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  1328. SIZE_T forwardedAddress = this->GetAddressFromExportTable(&addrStruct, (char*)(addr->BufferBaseAddress + *funcAddrPtr + RecurseDotIndex + 1), false);
  1329. delete[] exportDirectoryBuffer;
  1330. return forwardedAddress;
  1331. }
  1332. else
  1333. {
  1334. return EAT_ADDRESS_NOT_FOUND;
  1335. }
  1336. }
  1337. else
  1338. {
  1339. return EAT_ADDRESS_NOT_FOUND;
  1340. }
  1341. }
  1342. return (SIZE_T)(addr->BaseAddress + *funcAddrPtr);
  1343. }
  1344. }
  1345. }
  1346. }
  1347. return EAT_ADDRESS_NOT_FOUND;
  1348. }
  1349. // Attempts to retrieve function name associated to ordinal import from the export table of the loaded module.
  1350. // Returns a pointer to the function name if it exists. If the function is not found, the return value is NULL.
  1351. const char* PortableExecutable64::GetOrdinalFunctionNameFromExportTable(const AddrStruct* addr, const WORD ordinal) const
  1352. {
  1353. const WORD* const ordinals = (WORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNameOrdinals);
  1354. for (unsigned int i = 0; i < addr->ExportDirectory->NumberOfFunctions; ++i)
  1355. {
  1356. if ((addr->ExportDirectory->Base + ordinals[i]) == ordinal)
  1357. {
  1358. const DWORD* const stringPtr = (DWORD*)(addr->BufferBaseAddress + addr->ExportDirectory->AddressOfNames + i * sizeof(DWORD));
  1359. const Byte* const absStringPtr = (Byte*)(addr->BufferBaseAddress + *stringPtr);
  1360. // Make sure the string points inside of the buffer. Scrambled EAT would crash the application.
  1361. if (absStringPtr > (addr->BufferBaseAddress + addr->DirectoryAddress->Size) && absStringPtr < addr->BufferEndAddress)
  1362. {
  1363. return (const char*)absStringPtr;
  1364. }
  1365. }
  1366. }
  1367. return NULL;
  1368. }
  1369. // Retrieves the import table from the PE header of the loaded process. This information is stored in the global storage that has process lifetime.
  1370. const bool PortableExecutable64::GetImportAddressTable() const
  1371. {
  1372. // We use a return value to indicate whether function names can actually be retrieved using OriginalFirstThunk.
  1373. bool result = true;
  1374. // Read process memory into local buffer in order to load IAT.
  1375. Byte moduleBuffer[0x400];
  1376. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, 0x400, NULL);
  1377. const IMAGE_NT_HEADERS64* const pNTHeader = (IMAGE_NT_HEADERS*)((BYTE*)moduleBuffer + ((IMAGE_DOS_HEADER*)moduleBuffer)->e_lfanew);
  1378. // The PE Headers are not valid, the pointer runs outside the bounds of the buffer.
  1379. if ((Byte*)pNTHeader > (moduleBuffer + 0x400))
  1380. {
  1381. return false;
  1382. }
  1383. const IMAGE_OPTIONAL_HEADER* const pOptionalHeader = ((IMAGE_OPTIONAL_HEADER*)&pNTHeader->OptionalHeader);
  1384. // Read the import descriptor table into local memory.
  1385. unsigned int counter = 0;
  1386. IMAGE_IMPORT_DESCRIPTOR pDesc;
  1387. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (counter * sizeof(IMAGE_IMPORT_DESCRIPTOR))), &pDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR), NULL);
  1388. // Check whether OriginalFirstThunk is non-zero. If it is zero, the target process executable may be packed. We can find
  1389. // the function addresses, but we cannot find the function names directly.
  1390. if (!pDesc.OriginalFirstThunk)
  1391. {
  1392. result = false;
  1393. }
  1394. while (pDesc.FirstThunk && pDesc.Name != 0xFFFF)
  1395. {
  1396. // Read DLL name from import descriptor entry.
  1397. char dllName[48];
  1398. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(pDesc.Name + this->mBaseAddress), dllName, 48, NULL);
  1399. // Add new import descriptor to the table.
  1400. ImportTableDescriptor& impDesc = LoadedProcessPEInformation.ImportAddressTable.Add();
  1401. impDesc.ModuleName = dllName;
  1402. // Get base address and length of desired DLL, and look up the function foreign name in the export table of that DLL.
  1403. WString apiSetDllName = ToLower(dllName);
  1404. const Win32ModuleInformation* modBaseAddr = NULL;
  1405. // Check whether we have to deal with an ApiSet redirection or not.
  1406. if (apiSetDllName.StartsWith("api-ms-win") || apiSetDllName.StartsWith("ext-ms-win"))
  1407. {
  1408. // Windows ApiSetSchema redirection detected. Remove the file extension before resolving.
  1409. const int lastDot = apiSetDllName.ReverseFind('.');
  1410. if (lastDot != -1)
  1411. {
  1412. apiSetDllName.Remove(lastDot, apiSetDllName.GetLength() - lastDot);
  1413. }
  1414. // Recursively resolve the redirection.
  1415. while (!modBaseAddr)
  1416. {
  1417. // First remove the prefix, the resolving works without the prefix.
  1418. apiSetDllName.Remove(0, 4);
  1419. // Resolve the redirection.
  1420. const wchar* const outWString = this->InlineResolveApiSetSchema(apiSetDllName);
  1421. if (outWString)
  1422. {
  1423. apiSetDllName = outWString;
  1424. delete[] outWString;
  1425. // Get the module base address from the internal module list, and set the logical base address.
  1426. modBaseAddr = mModuleManager->FindModule(apiSetDllName.ToString());
  1427. impDesc.LogicalBaseAddress = modBaseAddr ? modBaseAddr->BaseAddress : 0;
  1428. }
  1429. }
  1430. }
  1431. else
  1432. {
  1433. // Get the module base address from the internal module list.
  1434. modBaseAddr = mModuleManager->FindModule(apiSetDllName.ToString());
  1435. impDesc.LogicalBaseAddress = 0;
  1436. }
  1437. // Does the module have a base address? If so, we parse its export table.
  1438. if (modBaseAddr)
  1439. {
  1440. impDesc.ModulePointer = modBaseAddr;
  1441. Byte dllBuffer[0x400];
  1442. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)modBaseAddr->BaseAddress, dllBuffer, 0x400, NULL);
  1443. const IMAGE_NT_HEADERS64* pNTHeader =(IMAGE_NT_HEADERS64*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  1444. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER64*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  1445. // Check whether the discovered module actually contains an export table.
  1446. if (dataDir.Size)
  1447. {
  1448. Byte* exportDirectoryBuffer = new Byte[dataDir.Size];
  1449. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(modBaseAddr->BaseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  1450. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  1451. AddrStruct addrStruct((Byte*)modBaseAddr->BaseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  1452. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  1453. IMAGE_THUNK_DATA thunk;
  1454. unsigned int count = 0;
  1455. do
  1456. {
  1457. // Try to read current thunk into local memory.
  1458. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pDesc.OriginalFirstThunk + count * sizeof(IMAGE_THUNK_DATA)), &thunk, sizeof(IMAGE_THUNK_DATA), NULL);
  1459. ImportAddressTableEntry funcEntry;
  1460. // Check for 64-bit ordinal magic flag.
  1461. if (thunk.u1.Ordinal & IMAGE_ORDINAL_FLAG64)
  1462. {
  1463. funcEntry.Ordinal = IMAGE_ORDINAL64(thunk.u1.Ordinal);
  1464. funcEntry.Hint = 0;
  1465. if (addrStruct.ExportDirectory->AddressOfNames)
  1466. {
  1467. funcEntry.FunctionName = this->GetOrdinalFunctionNameFromExportTable(&addrStruct, funcEntry.Ordinal);
  1468. }
  1469. }
  1470. else
  1471. {
  1472. char funcName[96];
  1473. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + thunk.u1.AddressOfData), funcName, 96, NULL);
  1474. // Set ordinal value to 0, read function name and WORD sized hint from the first two read bytes sequence.
  1475. funcEntry.Ordinal = 0;
  1476. funcEntry.Hint = *(WORD*)funcName;
  1477. funcEntry.FunctionName = funcName + sizeof(WORD);
  1478. }
  1479. // In a rare occasion the ordinal bit-flag is already removed. In this case the ordinal should be detected by section awareness.
  1480. if (funcEntry.FunctionName.IsEmpty() && !RVAPointsInsideSection((DWORD)thunk.u1.Ordinal))
  1481. {
  1482. funcEntry.Ordinal = (WORD)thunk.u1.Ordinal;
  1483. funcEntry.Hint = 0;
  1484. if (addrStruct.ExportDirectory->AddressOfNames)
  1485. {
  1486. funcEntry.FunctionName = this->GetOrdinalFunctionNameFromExportTable(&addrStruct, funcEntry.Ordinal);
  1487. }
  1488. }
  1489. // If the function name is empty even after ordinal resolving, the function has no name. Give it an automated name.
  1490. if (funcEntry.FunctionName.IsEmpty())
  1491. {
  1492. String localModName = dllName;
  1493. const int dotIndex = localModName.ReverseFind('.');
  1494. localModName.Remove(dotIndex, localModName.GetLength() - dotIndex);
  1495. funcEntry.FunctionName = Format("%s.%i", localModName, funcEntry.Ordinal);
  1496. }
  1497. // Save the thunk address of the function.
  1498. funcEntry.ThunkAddress = this->mBaseAddress + pDesc.FirstThunk + count++ * sizeof(SIZE_T);
  1499. // Read function address from thunk data and increment function iteration counter.
  1500. SIZE_T funcAddress;
  1501. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)funcEntry.ThunkAddress, &funcAddress, sizeof(SIZE_T), NULL);
  1502. if (!funcAddress)
  1503. {
  1504. continue;
  1505. }
  1506. funcEntry.VirtualAddress = funcAddress;
  1507. funcEntry.Flag = 0;
  1508. // Check whether actual address is equal to the address it should be, otherwise the IAT is hooked.
  1509. const SIZE_T eatAddress = this->GetAddressFromExportTable(&addrStruct, funcEntry.Ordinal ? (char*)funcEntry.Ordinal : funcEntry.FunctionName.Begin(), funcEntry.Ordinal ? 0 : funcEntry.FunctionName.GetLength());
  1510. if (eatAddress == EAT_ADDRESS_NOT_FOUND)
  1511. {
  1512. funcEntry.Flag = IAT_FLAG_NOT_FOUND;
  1513. }
  1514. else if (eatAddress != funcEntry.VirtualAddress)
  1515. {
  1516. funcEntry.Flag = IAT_FLAG_HOOKED;
  1517. }
  1518. // Add function to import descriptor.
  1519. impDesc.FunctionList.Add(funcEntry);
  1520. }
  1521. while (thunk.u1.AddressOfData);
  1522. delete[] exportDirectoryBuffer;
  1523. }
  1524. }
  1525. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(this->mBaseAddress + pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (++counter * sizeof(IMAGE_IMPORT_DESCRIPTOR))), &pDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR), NULL);
  1526. }
  1527. return result;
  1528. }
  1529. // Places a hook in the IAT, replacing the function address with another one.
  1530. // First parameter is either a pointer to a buffer containing the function name or an ordinal value.
  1531. bool PortableExecutable64::PlaceIATHook(const Win32ModuleInformation* modBase, const char* NameOrdinal, const SIZE_T newAddress, bool IsOrdinal) const
  1532. {
  1533. bool result = false;
  1534. Byte* const moduleBuffer = new Byte[modBase->Length];
  1535. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)this->mBaseAddress, moduleBuffer, modBase->Length, NULL);
  1536. const IMAGE_NT_HEADERS* const pNTHeader =(IMAGE_NT_HEADERS*)(moduleBuffer + ((IMAGE_DOS_HEADER*)moduleBuffer)->e_lfanew);
  1537. const IMAGE_IMPORT_DESCRIPTOR* pDesc = (IMAGE_IMPORT_DESCRIPTOR*)(moduleBuffer + ((IMAGE_OPTIONAL_HEADER*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  1538. // Additional sanity checking, to avoid pDesc to be located outside of the allocated buffer.
  1539. if ((Byte*)pDesc > moduleBuffer && (Byte*)pDesc < moduleBuffer + modBase->Length)
  1540. {
  1541. while (pDesc->FirstThunk)
  1542. {
  1543. // Read DLL name from import descriptor entry.
  1544. const char* const dllName = (char*)(moduleBuffer + pDesc->Name);
  1545. IMAGE_THUNK_DATA* thunk;
  1546. unsigned int count = 0;
  1547. do
  1548. {
  1549. IMAGE_THUNK_DATA* const curAddress = (IMAGE_THUNK_DATA*)(moduleBuffer + pDesc->OriginalFirstThunk + count * sizeof(IMAGE_THUNK_DATA));
  1550. // Read current thunk into local memory.
  1551. thunk = curAddress;
  1552. void* const AddressAddr = (void*)(this->mBaseAddress + pDesc->FirstThunk + count++ * sizeof(IMAGE_THUNK_DATA));
  1553. if (IsOrdinal)
  1554. {
  1555. if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
  1556. {
  1557. // Ordinal import detected, check whether ordinal matches input value.
  1558. if (IMAGE_ORDINAL64(thunk->u1.Ordinal) == (SIZE_T)NameOrdinal)
  1559. {
  1560. DWORD dwOldProtect;
  1561. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &dwOldProtect);
  1562. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, AddressAddr, &newAddress, sizeof(IMAGE_THUNK_DATA), NULL);
  1563. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(IMAGE_THUNK_DATA), dwOldProtect, &dwOldProtect);
  1564. result = true;
  1565. break;
  1566. }
  1567. }
  1568. }
  1569. else
  1570. {
  1571. // If the current import is not a named one, move over to the next.
  1572. if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
  1573. {
  1574. continue;
  1575. }
  1576. // Read function name from thunk data.
  1577. const char* const funcName = (char*)(moduleBuffer + thunk->u1.AddressOfData + sizeof(WORD));
  1578. // Named import detected, check whether import matches input name.
  1579. if (strcmp(funcName, NameOrdinal) == 0)
  1580. {
  1581. DWORD dwOldProtect;
  1582. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &dwOldProtect);
  1583. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, AddressAddr, &newAddress, sizeof(IMAGE_THUNK_DATA), NULL);
  1584. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, AddressAddr, sizeof(IMAGE_THUNK_DATA), dwOldProtect, &dwOldProtect);
  1585. result = true;
  1586. break;
  1587. }
  1588. }
  1589. }
  1590. while (thunk->u1.AddressOfData);
  1591. ++pDesc;
  1592. }
  1593. }
  1594. // Success, free used buffers and return.
  1595. delete[] moduleBuffer;
  1596. return result;
  1597. }
  1598. // Attempts to restore the PE headers from a file on the harddisk to a module loaded in memory.
  1599. // Retuns true if the operation succeeded and false if it did not succeed.
  1600. bool PortableExecutable64::RestorePEHeaderFromFile(const String& fileName, const Win32ModuleInformation& module) const
  1601. {
  1602. bool result = true;
  1603. // Create handle to file on the disk.
  1604. HANDLE hFile = CreateFile(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  1605. if (!hFile || hFile == INVALID_HANDLE_VALUE)
  1606. {
  1607. result = false;
  1608. }
  1609. // Get file size and read file into buffer.
  1610. LARGE_INTEGER size;
  1611. GetFileSizeEx(hFile, &size);
  1612. DWORD bytesRead;
  1613. Byte* const fileBuffer = new Byte[size.LowPart];
  1614. if (!ReadFile(hFile, fileBuffer, size.LowPart, &bytesRead, NULL))
  1615. {
  1616. result = false;
  1617. }
  1618. // Read header size.
  1619. const IMAGE_DOS_HEADER* const pDOSHeader = (IMAGE_DOS_HEADER*)fileBuffer;
  1620. if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
  1621. {
  1622. return false;
  1623. }
  1624. const IMAGE_NT_HEADERS* const pNTHeader =(IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
  1625. if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
  1626. {
  1627. result = false;
  1628. }
  1629. const IMAGE_OPTIONAL_HEADER* const pOptionalHeader = (IMAGE_OPTIONAL_HEADER*)&pNTHeader->OptionalHeader;
  1630. // Write header data into process memory at designated location.
  1631. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, pOptionalHeader->SizeOfHeaders, PAGE_READWRITE, &bytesRead);
  1632. if (!CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, fileBuffer, pOptionalHeader->SizeOfHeaders, NULL))
  1633. {
  1634. result = false;
  1635. }
  1636. CrySearchRoutines.CryProtectMemoryRoutine(this->mProcessHandle, (void*)module.BaseAddress, pOptionalHeader->SizeOfHeaders, bytesRead, &bytesRead);
  1637. delete[] fileBuffer;
  1638. CloseHandle(hFile);
  1639. return result;
  1640. }
  1641. // Attempts to hide a module from the loaded process. Hiding means it not being visible for debuggers anymore.
  1642. // Returns true if the operation succeeded, and false if it did not succeed.
  1643. bool PortableExecutable64::HideModuleFromProcess(const Win32ModuleInformation& module) const
  1644. {
  1645. if (!CrySearchRoutines.NtQueryInformationProcess)
  1646. {
  1647. return false;
  1648. }
  1649. // Retrieve target process information using Nt function.
  1650. PROCESS_BASIC_INFORMATION procBlock;
  1651. if (CrySearchRoutines.NtQueryInformationProcess(this->mProcessHandle, ProcessBasicInformation, &procBlock, sizeof(procBlock), NULL) != STATUS_SUCCESS)
  1652. {
  1653. return false;
  1654. }
  1655. PEB_LDR_DATA peb;
  1656. PPEB_LDR_DATA pebPtr;
  1657. // Read process environment block and loader data from the process memory.
  1658. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (unsigned char*)procBlock.PebBaseAddress + offsetof(PEB, LoaderData), &pebPtr, sizeof(PPEB_LDR_DATA), NULL);
  1659. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, pebPtr, &peb, sizeof(PEB_LDR_DATA), NULL);
  1660. LDR_MODULE curModule;
  1661. bool found = false;
  1662. int retryCount = 0;
  1663. int moduleCount = 0;
  1664. LIST_ENTRY* Head = peb.InMemoryOrderModuleList.Flink;
  1665. LIST_ENTRY* Node = Head;
  1666. do
  1667. {
  1668. // Read current linked list module from the process memory.
  1669. if (CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, --Node, &curModule, sizeof(LDR_MODULE), NULL))
  1670. {
  1671. if (curModule.BaseAddress)
  1672. {
  1673. // some applications cause an infinite loop. This is one way to help preventing it.
  1674. ++moduleCount;
  1675. // A valid module is found, read its base dll name from the process memory.
  1676. wchar BaseDllName[MAX_PATH];
  1677. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, curModule.BaseDllName.Buffer, BaseDllName, curModule.BaseDllName.Length, NULL);
  1678. BaseDllName[curModule.BaseDllName.Length / 2] = 0;
  1679. PathStripPathW(BaseDllName);
  1680. // Compare current module's base name and desired module name, if it matches, the desired one is found.
  1681. String selModName = mModuleManager->GetModuleFilename(module.BaseAddress);
  1682. if (memcmp(selModName.ToWString().Begin(), BaseDllName, selModName.GetLength() * sizeof(wchar)) == 0)
  1683. {
  1684. found = true;
  1685. for (unsigned int index = 0; index < 3; Node++, index++)
  1686. {
  1687. LIST_ENTRY current;
  1688. // Read current, previous and next list entry from the process memory.
  1689. BOOL localRes = CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, Node, &current, sizeof(LIST_ENTRY), NULL);
  1690. if (!localRes)
  1691. {
  1692. found = false;
  1693. break;
  1694. }
  1695. const unsigned __int64 nextItemAddr = (unsigned __int64)current.Flink;
  1696. const unsigned __int64 prevItemAddr = (unsigned __int64)current.Blink;
  1697. // Overwrite the pointers of the previous and next list entry so the current one is effectively hidden.
  1698. localRes = CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, current.Blink, &nextItemAddr, sizeof(LIST_ENTRY*), NULL);
  1699. localRes = CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, (unsigned char*)current.Flink + sizeof(LIST_ENTRY*), &prevItemAddr, sizeof(LIST_ENTRY*), NULL);
  1700. }
  1701. break;
  1702. }
  1703. }
  1704. }
  1705. else
  1706. {
  1707. // Prevent infinite while looping. In most situations this code may be unnessecary.
  1708. if (++retryCount == 3)
  1709. {
  1710. break;
  1711. }
  1712. }
  1713. // Desired module was not yet found, traverse to the next one.
  1714. Node = curModule.InMemoryOrderModuleList.Flink;
  1715. }
  1716. while(Head != Node && moduleCount < mModuleManager->GetModuleCount());
  1717. return found;
  1718. }
  1719. // Dumps a specific section in the loaded process to a file on the harddisk.
  1720. // Returns true if the operation succeeded, and false if it did not succeed.
  1721. bool PortableExecutable64::DumpProcessSection(const String& fileName, const SIZE_T address, const SIZE_T size) const
  1722. {
  1723. bool result = true;
  1724. Byte* const buffer = new Byte[size];
  1725. SIZE_T bytesRead;
  1726. if (!CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)address, buffer, size, &bytesRead)
  1727. && bytesRead == 0)
  1728. {
  1729. delete[] buffer;
  1730. return false;
  1731. }
  1732. // Create dmp file on the disk.
  1733. HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1734. if (hFile == INVALID_HANDLE_VALUE)
  1735. {
  1736. result = false;
  1737. }
  1738. // Write the data read to the file.
  1739. DWORD bytesWritten;
  1740. if (!WriteFile(hFile, buffer, (DWORD)bytesRead, &bytesWritten, NULL))
  1741. {
  1742. DeleteFile(fileName);
  1743. result = false;
  1744. }
  1745. // All succeeded, free resources and return.
  1746. CloseHandle(hFile);
  1747. delete[] buffer;
  1748. return result;
  1749. }
  1750. // Attempts to load a dynamic link library into the target process.
  1751. // Returns true if the operation succeeded, and false if it did not succeed.
  1752. bool PortableExecutable64::LoadLibraryExternal(const String& library) const
  1753. {
  1754. // Allocate memory space for the library path.
  1755. void* const lpRemoteAddress = VirtualAllocEx(this->mProcessHandle, NULL, library.GetLength(), MEM_COMMIT, PAGE_READWRITE);
  1756. SIZE_T bytesWritten;
  1757. // Write path to library into the newly allocated memory.
  1758. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpRemoteAddress, library, library.GetLength(), &bytesWritten);
  1759. if (bytesWritten != library.GetLength())
  1760. {
  1761. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1762. return false;
  1763. }
  1764. // Create a thread remotely that executes LoadLibraryA, pointing to the allocated string as parameter.
  1765. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "LoadLibraryA"), lpRemoteAddress, NULL, NULL);
  1766. // Succesfully created thread, wait for it to complete and free resources after.
  1767. if (hThread && hThread != INVALID_HANDLE_VALUE)
  1768. {
  1769. WaitForSingleObject(hThread, 5000);
  1770. CloseHandle(hThread);
  1771. }
  1772. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1773. return !!hThread;
  1774. }
  1775. // Attempts to load a dynamic link library into the target process.
  1776. // Returns true if the operation succeeded, and false if it did not succeed.
  1777. bool PortableExecutable64::LoadLibraryExternalHijack(const String& library, HANDLE hThread) const
  1778. {
  1779. // If the thread wasn't opened, the function returns.
  1780. if (!hThread || hThread == INVALID_HANDLE_VALUE)
  1781. {
  1782. return false;
  1783. }
  1784. // Allocate memory space for the library path.
  1785. void* const lpRemoteAddress = VirtualAllocEx(this->mProcessHandle, NULL, library.GetLength(), MEM_COMMIT, PAGE_READWRITE);
  1786. SIZE_T bytesWritten;
  1787. // Write path to library into the newly allocated memory.
  1788. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpRemoteAddress, library, library.GetLength(), &bytesWritten);
  1789. if (bytesWritten != library.GetLength())
  1790. {
  1791. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1792. return false;
  1793. }
  1794. // The shellcode that is written and executed inside the target program:
  1795. // sub rsp, 8
  1796. // mov dword ptr [rsp], 0xCCCCCCCC
  1797. // mov dword ptr [rsp+4], 0xCCCCCCCC
  1798. // push rax
  1799. // push rbx
  1800. // push rcx
  1801. // push rdx
  1802. // push r8
  1803. // push r9
  1804. // push r10
  1805. // push r11
  1806. // movabs rbx, 0xCCCCCCCCCCCCCCCC
  1807. // movabs rcx, 0xCCCCCCCCCCCCCCCC
  1808. // sub rsp, 32
  1809. // call rbx
  1810. // add rsp, 32
  1811. // pop r11
  1812. // pop r10
  1813. // pop r9
  1814. // pop r8
  1815. // pop rdx
  1816. // pop rcx
  1817. // pop rbx
  1818. // movabs rax, 0xCCCCCCCCCCCCCCCC
  1819. // mov dword ptr [rax], 0x1337
  1820. // pop rax
  1821. // ret
  1822. Byte shellCode[] = { 0x48, 0x83, 0xEC, 0x08, 0xC7, 0x04, 0x24, 0xCC, 0xCC, 0xCC, 0xCC, 0xC7, 0x44, 0x24, 0x04, 0xCC, 0xCC, 0xCC,
  1823. 0xCC, 0x50, 0x53, 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x48, 0xBB, 0xCC, 0xCC, 0xCC,
  1824. 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0xB9, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x48, 0x83, 0xEC,
  1825. 0x20, 0xFF, 0xD3, 0x48, 0x83, 0xC4, 0x20, 0x41, 0x5B, 0x41, 0x5A, 0x41, 0x59, 0x41, 0x58, 0x5A, 0x59, 0x5B,
  1826. 0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xC7, 0x00, 0x37, 0x13, 0x00, 0x00, 0x58, 0xC3 };
  1827. // Allocate executable block of memory for the shellcode.
  1828. void* const lpShellCode = VirtualAllocEx(this->mProcessHandle, NULL, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  1829. const SIZE_T flagAddress = (SIZE_T)lpShellCode + 0x100;
  1830. // Suspend the opened thread.
  1831. SuspendThread(hThread);
  1832. // Create context, aligned to 64-bits boundary for x64.
  1833. void* const ctxBase = VirtualAlloc(NULL, sizeof(CONTEXT) + 8, MEM_COMMIT, PAGE_READWRITE);
  1834. PCONTEXT const ctx = (PCONTEXT)ctxBase;
  1835. AlignPointer((DWORD_PTR*)&ctx, 8);
  1836. memset(ctx, 0, sizeof(CONTEXT));
  1837. ctx->ContextFlags = CONTEXT_FULL;
  1838. GetThreadContext(hThread, ctx);
  1839. PLARGE_INTEGER rip64large = (PLARGE_INTEGER)&ctx->Rip;
  1840. // Fix up dynamic addresses inside shellcode.
  1841. *(DWORD*)&shellCode[7] = rip64large->LowPart;
  1842. *(DWORD*)&shellCode[15] = rip64large->HighPart;
  1843. *(SIZE_T*)&shellCode[33] = (SIZE_T)LoadLibraryA;
  1844. *(SIZE_T*)&shellCode[43] = (SIZE_T)lpRemoteAddress;
  1845. *(SIZE_T*)&shellCode[74] = flagAddress;
  1846. // Write the shellcode to the remotely allocated buffer.
  1847. CrySearchRoutines.CryWriteMemoryRoutine(this->mProcessHandle, lpShellCode, shellCode, sizeof(shellCode), &bytesWritten);
  1848. if (bytesWritten != sizeof(shellCode))
  1849. {
  1850. VirtualFreeEx(this->mProcessHandle, lpShellCode, 0, MEM_RELEASE);
  1851. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1852. return false;
  1853. }
  1854. // Change RIP to resume execution at the shellcode.
  1855. ctx->Rip = (SIZE_T)lpShellCode;
  1856. // Place the new context inside the thread.
  1857. SetThreadContext(hThread, ctx);
  1858. // Flush the instruction cache to avoid problems with cached instructions.
  1859. FlushInstructionCache(this->mProcessHandle, lpShellCode, sizeof(shellCode));
  1860. // Resume the thread to let the DLL load and close thread handle.
  1861. ResumeThread(hThread);
  1862. // Sample the completion flag to contain the magic number 0x1337. Block the thread until the sampling is succesful.
  1863. DWORD magic = 0;
  1864. unsigned int threshold = 0;
  1865. do
  1866. {
  1867. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)flagAddress, &magic, sizeof(DWORD), &bytesWritten);
  1868. // Prevent CrySearch to start eating CPU time while still trying to have an accurate sample.
  1869. Sleep(75);
  1870. ++threshold;
  1871. }
  1872. while (magic != 0x1337 && threshold < THREAD_HIJACK_MAGIC_PROBE_THRESHOLD);
  1873. // The loop finished, free memory pages and close thread handle.
  1874. VirtualFreeEx(this->mProcessHandle, lpShellCode, 0, MEM_RELEASE);
  1875. VirtualFreeEx(this->mProcessHandle, lpRemoteAddress, 0, MEM_RELEASE);
  1876. CloseHandle(hThread);
  1877. VirtualFree(ctxBase, 0, MEM_RELEASE);
  1878. return (threshold != THREAD_HIJACK_MAGIC_PROBE_THRESHOLD);
  1879. }
  1880. // Attempts to unload a loaded module from the target process.
  1881. void PortableExecutable64::UnloadLibraryExternal(const SIZE_T module) const
  1882. {
  1883. // Create a thread remotely that executes FreeLibrary, with module handle as parameter.
  1884. HANDLE hThread = CreateRemoteThread(this->mProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "FreeLibrary"), (void*)module, NULL, NULL);
  1885. // Succesfully created thread, wait for it to complete and free resources after.
  1886. if (hThread && hThread != INVALID_HANDLE_VALUE)
  1887. {
  1888. WaitForSingleObject(hThread, 5000);
  1889. CloseHandle(hThread);
  1890. }
  1891. }
  1892. // Restores the original address of an imported function from the export table.
  1893. void PortableExecutable64::RestoreExportTableAddressImport(const Win32ModuleInformation* modBase, const SIZE_T baseAddress, const char* NameOrdinal, const int NameLength) const
  1894. {
  1895. Byte* const dllBuffer = new Byte[0x400];
  1896. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)baseAddress, dllBuffer, 0x400, NULL);
  1897. const IMAGE_NT_HEADERS64* const pNTHeader =(IMAGE_NT_HEADERS64*)(dllBuffer + ((IMAGE_DOS_HEADER*)dllBuffer)->e_lfanew);
  1898. IMAGE_DATA_DIRECTORY dataDir = *(&((IMAGE_OPTIONAL_HEADER64*)&pNTHeader->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
  1899. delete[] dllBuffer;
  1900. // Check whether the discovered module actually has an export table.
  1901. if (dataDir.Size)
  1902. {
  1903. Byte* const exportDirectoryBuffer = new Byte[dataDir.Size];
  1904. CrySearchRoutines.CryReadMemoryRoutine(this->mProcessHandle, (void*)(baseAddress + dataDir.VirtualAddress), exportDirectoryBuffer, dataDir.Size, NULL);
  1905. Byte* const bufBase = exportDirectoryBuffer - dataDir.VirtualAddress;
  1906. AddrStruct addrStruct((Byte*)baseAddress, (exportDirectoryBuffer - dataDir.VirtualAddress), bufBase + dataDir.VirtualAddress + dataDir.Size
  1907. , &dataDir, (IMAGE_EXPORT_DIRECTORY*)exportDirectoryBuffer);
  1908. this->PlaceIATHook(modBase, NameOrdinal, this->GetAddressFromExportTable(&addrStruct, NameOrdinal, NameLength), !NameLength);
  1909. delete[] exportDirectoryBuffer;
  1910. }
  1911. }
  1912. #endif