/********************************************************* * ReadMmdModelMaterials関数 * * PMDとPMXのテクスチャ画像データを読み込む * * 引数 * * data : 画像データのアーカイブデータ * * data_size : 画像データのアーカイブデータのサイズ * * num_data : 画像データの数 * * 返り値 * * テクスチャ画像のファイル名とデータ位置・サイズの配列 * *********************************************************/ MATERIAL_ARCHIVE_DATA* ReadMmdModelMaterials( uint8* data, size_t data_size, int* num_data ) { MEMORY_STREAM stream = {data, 0, data_size, 1}; MATERIAL_ARCHIVE_DATA *datas; int num_images; uint32 data32; int i; // 画像データの数を読み込む (void)MemRead(&data32, sizeof(data32), 1, &stream); num_images = *num_data = (int)data32; datas = (MATERIAL_ARCHIVE_DATA*)MEM_ALLOC_FUNC(sizeof(*datas)*num_images); for(i=0; i<num_images; i++) { (void)MemRead(&data32, sizeof(data32), 1, &stream); datas[i].name = (char*)&stream.buff_ptr[stream.data_point]; (void)MemSeek(&stream, data32, SEEK_CUR); (void)MemRead(&data32, sizeof(data32), 1, &stream); datas[i].data_start = data32; (void)MemRead(&data32, sizeof(data32), 1, &stream); datas[i].data_size = data32; } return datas; }
void RiotSkeleton::load(const void* data, size_t length) { dispose(); char* ptr = (char*)data; header = MemRead(ptr, SKL::Header_t); SKLenforce(std::string(header.mMagic, 8) == "r3d2sklt", "Magic header wrong when trying to load SKN file"); SKLenforce(0 < header.mVersion && header.mVersion < 3, "Unsupported version of SKL file(Supports version 1 & 2)"); if (header.mVersion == 1 || header.mVersion == 2) { designerId = MemRead(ptr, unsigned int); auto boneCount = MemRead(ptr, unsigned int); bones.reserve(boneCount); for (unsigned int idx = 0; idx < boneCount; idx++) { auto bone = MemRead(ptr, SKL::Bone_t); bones.push_back(bone); } if (header.mVersion == 1) { for (unsigned int idx = 0; idx < boneCount; idx++) { boneIds.push_back(idx); } } else { auto boneIdCount = MemRead(ptr, unsigned int); boneIds.reserve(boneIdCount); for (unsigned int idx = 0; idx < boneIdCount; idx++) { auto boneId = MemRead(ptr, unsigned int); boneIds.push_back(boneId); } } }
void RiotSkin::load(const void* data, size_t length) { dispose(); char* ptr = (char*)data; header = MemRead(ptr, SKN::Header_t); SKNenforce(header.mMagic == 0x112233, "Magic header wrong when trying to load SKN file"); SKNenforce(0 < header.mVersion && header.mVersion < 3, "Unsupported version of SKN file(Supports version 1 & 2)"); toc = MemRead(ptr, SKN::TableOfContents_t); SKN::MaterialHeader_t material; for (unsigned int idx = 0; idx < toc.mMaterialCount; idx++) { material = MemRead(ptr, SKN::MaterialHeader_t); materialHeaders.push_back(material); } meshHeader = MemRead(ptr, SKN::MeshHeader_t); indices.reserve(meshHeader.mIndexCount); unsigned short *indexPtr = (unsigned short*)ptr; indices.insert(indices.end(), indexPtr, indexPtr + meshHeader.mIndexCount); ptr += meshHeader.mIndexCount * sizeof(unsigned short); SKN::Vertex_t* vertPtr = (SKN::Vertex_t*)ptr; vertices.reserve(meshHeader.mVertexCount); vertices.insert(vertices.end(), vertPtr, vertPtr + meshHeader.mVertexCount); ptr += meshHeader.mVertexCount * sizeof(SKN::Vertex_t); if (header.mVersion == 2) { endData = MemRead(ptr, SKN::EndData_t); } if (true) { std::cout << "SKN magic: " << header.mMagic << std::endl; std::cout << "SKN version: " << header.mVersion << std::endl; std::cout << "SKN objects: " << toc.mObjectCount << std::endl; std::cout << "SKN materials: " << toc.mMaterialCount << std::endl; for (auto material : materialHeaders) { std::cout << "\t" << material.mMaterialName << " " << material.mVertexCount << " " << material.mVertexCount << std::endl; } std::cout << "SKN vertices: " << meshHeader.mVertexCount << std::endl; std::cout << "SKN indices: " << meshHeader.mIndexCount << std::endl; int max = 0; std::set<int> referenced; for (auto vert : vertices) { for (int i = 0; i < 4; i++) { max = max < vert.mBoneIndices[i] ? vert.mBoneIndices[i] : max; referenced.insert(vert.mBoneIndices[i]); } } std::cout << "SKN max referenced boneid: " << max << std::endl; std::cout << "SKN unique referenced boneid: " << referenced.size() << std::endl; for (auto idx : referenced) { std::cout << "\t" << idx << std::endl; } std::cout << std::endl; } }
bool disasmfast(duint addr, BASIC_INSTRUCTION_INFO* basicinfo) { unsigned int data[16]; if(!MemRead(addr, data, sizeof(data))) return false; return disasmfast((unsigned char*)data, addr, basicinfo); }
Analysis::Analysis(duint base, duint size) { _base = base; _size = size; _data = new unsigned char[_size + MAX_DISASM_BUFFER]; MemRead(_base, _data, _size); }
int disasmgetsize(uint addr) { char data[MAX_DISASM_BUFFER]; if(!MemRead(addr, data, sizeof(data))) return 1; return disasmgetsize(addr, (unsigned char*)data); }
SCRIPT_EXPORT duint Script::Pattern::FindMem(duint start, duint size, const char* pattern) { Memory<unsigned char*> data(size, "Script::Pattern::FindMem::data"); if(!MemRead((void*)start, data(), size, nullptr)) return -1; return Pattern::Find(data(), data.size(), pattern) + start; }
bool ExHandlerGetUnhandled(std::vector<duint> & Entries) { // Try the address for Windows Vista+ static duint addr_BasepCurrentTopLevelFilter = 0; #ifdef _WIN64 auto symbol = "BasepCurrentTopLevelFilter"; #else auto symbol = "_BasepCurrentTopLevelFilter"; #endif if(addr_BasepCurrentTopLevelFilter || valfromstring(symbol, &addr_BasepCurrentTopLevelFilter)) { // Read external pointer duint handlerValue = 0; if(!MemRead(addr_BasepCurrentTopLevelFilter, &handlerValue, sizeof(duint))) return false; // Decode with remote process cookie if(!MemDecodePointer(&handlerValue, true)) return false; Entries.push_back(handlerValue); return true; } return false; }
bool Process::MemWritePattern(ptr data, size_t datasize, const Pattern::WildcardPattern & pattern, bool safe) { std::vector<uint8> buffer(datasize); if (!MemRead(data, buffer.data(), datasize, nullptr, safe)) return false; Pattern::Write(buffer.data(), datasize, pattern); return MemWrite(data, buffer.data(), datasize, nullptr, safe); }
SCRIPT_EXPORT void Script::Pattern::WriteMem(duint start, duint size, const char* pattern) { Memory<unsigned char*> data(size, "Script::Pattern::WriteMem::data"); if(!MemRead((void*)start, data(), data.size(), nullptr)) return; patternwrite(data(), data.size(), pattern); MemWrite((void*)start, data(), data.size(), nullptr); }
bool ThreadGetTib(duint TEBAddress, NT_TIB* Tib) { // Calculate offset from structure member TEBAddress += offsetof(TEB, Tib); memset(Tib, 0, sizeof(NT_TIB)); return MemRead(TEBAddress, Tib, sizeof(NT_TIB)); }
ptr Process::MemFindPattern(ptr data, size_t datasize, const uint8* pattern, size_t patternsize, bool safe) const { std::vector<uint8> buffer(datasize); if (!MemRead(data, buffer.data(), datasize, nullptr, safe)) return 0; auto found = Pattern::Find(buffer.data(), datasize, pattern, patternsize); return found == -1 ? 0 : found + data; }
bool Process::MemSearchAndReplace(ptr data, size_t datasize, const Pattern::WildcardPattern & searchpattern, const Pattern::WildcardPattern & replacepattern, bool safe) { std::vector<uint8> buffer(datasize); if (!MemRead(data, buffer.data(), datasize, nullptr, safe)) return false; if (!Pattern::SearchAndReplace(buffer.data(), datasize, searchpattern, replacepattern)) return false; return MemWrite(data, buffer.data(), datasize, nullptr, safe); }
DWORD ThreadGetLastErrorTEB(ULONG_PTR ThreadLocalBase) { // Get the offset for the TEB::LastErrorValue and read it DWORD lastError = 0; duint structOffset = ThreadLocalBase + offsetof(TEB, LastErrorValue); MemRead(structOffset, &lastError, sizeof(DWORD)); return lastError; }
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO & refInfo, Capstone & cp, bool initCallBack, CBPROGRESS cbUpdateProgress) { // Allocate and read a buffer from the remote process Memory<unsigned char*> data(scanSize, "reffind:data"); if(!MemRead(scanStart, data(), scanSize)) { if(!Silent) dprintf("Error reading memory in reference search\n"); return 0; } if(initCallBack) Callback(0, 0, &refInfo); //concurrency::parallel_for(duint (0), scanSize, [&](duint i) for(duint i = 0; i < scanSize;) { // Print the progress every 4096 bytes if((i % 0x1000) == 0) { // Percent = (current / total) * 100 // Integer = floor(percent) int percent = (int)floor(((float)i / (float)scanSize) * 100.0f); cbUpdateProgress(percent); } // Disassemble the instruction int disasmMaxSize = min(MAX_DISASM_BUFFER, (int)(scanSize - i)); // Prevent going past the boundary int disasmLen = 1; if(cp.Disassemble(scanStart, data() + i, disasmMaxSize)) { BASIC_INSTRUCTION_INFO basicinfo; fillbasicinfo(&cp, &basicinfo); if(Callback(&cp, &basicinfo, &refInfo)) refInfo.refcount++; disasmLen = cp.Size(); } else { // Invalid instruction detected, so just skip the byte } scanStart += disasmLen; i += disasmLen; } cbUpdateProgress(100); return refInfo.refcount; }
void Pmd2BoneReadEnglishName(PMD2_BONE* bone, MEMORY_STREAM_PTR stream, int index) { if(index >= 0) { char name[BONE_NAME_SIZE+1]; (void)MemSeek(stream, BONE_NAME_SIZE*index, SEEK_SET); (void)MemRead(name, BONE_NAME_SIZE, 1, stream); bone->interface_data.english_name = EncodeText( &bone->application->encode, name, BONE_NAME_SIZE); } }
bool ExHandlerGetVCH(std::vector<duint> & Entries, bool UseVEH) { // VECTORED_HANDLER_LIST LdrpVectorHandlerList[2]; static duint addr_LdrpVectorHandlerList = 0; if(!addr_LdrpVectorHandlerList && !valfromstring("ntdll:LdrpVectorHandlerList", &addr_LdrpVectorHandlerList)) return false; // Increase array index when using continue handlers if(!UseVEH) addr_LdrpVectorHandlerList += (1 * sizeof(VECTORED_HANDLER_LIST)); // Read head entry VECTORED_HANDLER_LIST list; memset(&list, 0, sizeof(VECTORED_HANDLER_LIST)); if(!MemRead(addr_LdrpVectorHandlerList, &list, sizeof(VECTORED_HANDLER_LIST))) return false; // Sub-entries in list duint listCurrent = (duint)list.Next; duint listEnd = addr_LdrpVectorHandlerList; while(listCurrent && listCurrent != listEnd) { duint handler = (duint)list.VectoredHandler; MemDecodePointer(&handler); Entries.push_back(handler); // Move to next element memset(&list, 0, sizeof(VECTORED_HANDLER_LIST)); if(!MemRead(listCurrent, &list, sizeof(VECTORED_HANDLER_LIST))) break; listCurrent = (duint)list.Next; } return true; }
SCRIPT_EXPORT bool Script::Pattern::SearchAndReplaceMem(duint start, duint size, const char* searchpattern, const char* replacepattern) { Memory<unsigned char*> data(size, "Script::Pattern::SearchAndReplaceMem::data"); if(!MemRead((void*)start, data(), size, nullptr)) return false; duint found = patternfind(data(), data.size(), searchpattern); if(found == -1) return false; patternwrite(data() + found, data.size() - found, replacepattern); MemWrite((void*)(start + found), data() + found, data.size() - found, nullptr); return true; }
bool disasmispossiblestring(uint addr) { unsigned char data[11]; memset(data, 0, sizeof(data)); if(!MemRead(addr, data, sizeof(data) - 3)) return false; uint test = 0; memcpy(&test, data, sizeof(uint)); if(isasciistring(data, sizeof(data)) || isunicodestring(data, _countof(data))) return true; return false; }
bool ExHandlerGetVEH(std::vector<duint> & Entries) { // Try the address for Windows XP first (or older) // // VECTORED_EXCEPTION_NODE RtlpCalloutEntryList; static duint addr_RtlpCalloutEntryList = 0; if(addr_RtlpCalloutEntryList || valfromstring("ntdll:RtlpCalloutEntryList", &addr_RtlpCalloutEntryList)) { // Read header node VECTORED_EXCEPTION_NODE node; memset(&node, 0, sizeof(VECTORED_EXCEPTION_NODE)); if(!MemRead(addr_RtlpCalloutEntryList, &node, sizeof(VECTORED_EXCEPTION_NODE))) return false; // Move to the next link duint listCurrent = (duint)node.ListEntry.Flink; duint listEnd = addr_RtlpCalloutEntryList; while(listCurrent && listCurrent != listEnd) { duint handler = (duint)node.handler; MemDecodePointer(&handler); Entries.push_back(handler); // Move to next element memset(&node, 0, sizeof(VECTORED_EXCEPTION_NODE)); if(!MemRead(listCurrent, &node, sizeof(VECTORED_EXCEPTION_NODE))) break; listCurrent = (duint)node.ListEntry.Flink; } } // Otherwise try the Windows Vista or newer version return ExHandlerGetVCH(Entries, true); }
void ReadPmd2Bone( PMD2_BONE* bone, MEMORY_STREAM_PTR stream, PMD_DATA_INFO* info, size_t* data_size ) { BONE_UNIT unit; (void)MemRead(unit.name, 1, sizeof(unit.name), stream); (void)MemRead(&unit.parent_bone_id, sizeof(unit.parent_bone_id), 1, stream); (void)MemRead(&unit.child_bone_id, sizeof(unit.child_bone_id), 1, stream); (void)MemRead(&unit.type, sizeof(unit.type), 1, stream); (void)MemRead(&unit.target_bone_id, sizeof(unit.target_bone_id), 1, stream); (void)MemRead(&unit.position, sizeof(unit.position), 1, stream); bone->interface_data.name = EncodeText(&bone->application->encode, (char*)unit.name, sizeof(unit.name)); bone->child_bone_index = unit.child_bone_id; bone->parent_bone_index = unit.parent_bone_id; bone->target_bone_index = unit.target_bone_id; bone->type = (ePMD2_BONE_TYPE)unit.type; SET_POSITION(bone->origin, unit.position); COPY_VECTOR3(bone->offset, bone->origin); *data_size = PMD_BONE_UNIT_SIZE; }
bool ExHandlerGetVCH(std::vector<duint> & Entries, bool GetVEH) { // VECTORED_HANDLER_LIST LdrpVectorHandlerList[2]; static duint addr_LdrpVectorHandlerList = 0; duint addrInc = sizeof(duint); //Vista+ has an extra ULONG_PTR in front of the structure #ifdef _WIN64 auto symbol = "LdrpVectorHandlerList"; #else auto symbol = "_LdrpVectorHandlerList"; #endif if(!addr_LdrpVectorHandlerList && !valfromstring(symbol, &addr_LdrpVectorHandlerList)) return false; // Increase array index when using continue handlers if(!GetVEH) addrInc += sizeof(duint) + sizeof(LIST_ENTRY); //Vista+ has an extra ULONG_PTR // Read head entry auto list_head = addr_LdrpVectorHandlerList + addrInc; duint cur_entry; if(!MemRead(list_head, &cur_entry, sizeof(cur_entry))) return false; auto count = 0; while(cur_entry != list_head && count++ < MAX_HANDLER_DEPTH) { VEH_ENTRY_VISTA entry; if(!MemRead(cur_entry, &entry, sizeof(entry))) return false; auto handler = entry.VectoredHandler; if(!MemDecodePointer(&handler, true)) return false; Entries.push_back(handler); if(!MemRead(cur_entry, &cur_entry, sizeof(cur_entry))) return false; } return true; }
bool ExHandlerGetVEH(std::vector<duint> & Entries) { // Try the address for Windows XP first (or older) // // VECTORED_EXCEPTION_NODE RtlpCalloutEntryList; static duint addr_RtlpCalloutEntryList = 0; #ifdef _WIN64 auto symbol = "RtlpCalloutEntryList"; #else auto symbol = "_RtlpCalloutEntryList"; #endif if(addr_RtlpCalloutEntryList || valfromstring(symbol, &addr_RtlpCalloutEntryList)) { // Read head entry auto list_head = addr_RtlpCalloutEntryList; duint cur_entry; if(!MemRead(list_head, &cur_entry, sizeof(cur_entry))) return false; auto count = 0; while(cur_entry != list_head && count++ < MAX_HANDLER_DEPTH) { VEH_ENTRY_XP entry; if(!MemRead(cur_entry, &entry, sizeof(entry))) return false; auto handler = entry.VectoredHandler; MemDecodePointer(&handler, false); //TODO: Windows XP doesn't allow a remote process to query this value Entries.push_back(handler); if(!MemRead(cur_entry, &cur_entry, sizeof(cur_entry))) return false; } return true; } // Otherwise try the Windows Vista or newer version return ExHandlerGetVCH(Entries, true); }
int Pmd2JointPreparse(MEMORY_STREAM_PTR stream, PMD_DATA_INFO* info) { int32 size; if(MemRead(&size, sizeof(size), 1, stream) == 0 || size * PMD2_JOINT_UNIT_SIZE > stream->data_size - stream->data_point) { return FALSE; } info->joints_count = size; info->joints = &stream->buff_ptr[stream->data_point]; (void)MemSeek(stream, size * PMD2_JOINT_UNIT_SIZE, SEEK_CUR); return TRUE; }
void PmxJointRead(PMX_JOINT* joint, uint8* data, PMX_DATA_INFO* info, size_t* data_size) { PMX_JOINT_UNIT unit; MEMORY_STREAM stream = {data, 0, (size_t)(info->end - data), 1}; char *name_ptr; int length; TEXT_ENCODE *encode = info->encoding; uint8 type; // 日本語名 length = GetTextFromStream((char*)data, &name_ptr); joint->name = EncodeText(encode, name_ptr, length); stream.data_point = sizeof(int32) + length; // 英語名 length = GetTextFromStream((char*)&data[stream.data_point], &name_ptr); joint->english_name = EncodeText(encode, name_ptr, length); stream.data_point += sizeof(int32) + length; type = data[stream.data_point]; stream.data_point++; joint->type = (eJOINT_TYPE)type; joint->rigid_body1_index = GetSignedValue(&data[stream.data_point], (int)info->rigid_body_index_size); stream.data_point += info->rigid_body_index_size; joint->rigid_body2_index = GetSignedValue(&data[stream.data_point], (int)info->rigid_body_index_size); stream.data_point += info->rigid_body_index_size; (void)MemRead(unit.position, sizeof(unit.position), 1, &stream); (void)MemRead(unit.rotation, sizeof(unit.rotation), 1, &stream); (void)MemRead(unit.position_lower_limit, sizeof(unit.position_lower_limit), 1, &stream); (void)MemRead(unit.position_upper_limit, sizeof(unit.position_upper_limit), 1, &stream); (void)MemRead(unit.rotation_lower_limit, sizeof(unit.rotation_lower_limit), 1, &stream); (void)MemRead(unit.rotation_upper_limit, sizeof(unit.rotation_upper_limit), 1, &stream); (void)MemRead(unit.position_stiffness, sizeof(unit.position_stiffness), 1, &stream); (void)MemRead(unit.rotation_stiffness, sizeof(unit.rotation_stiffness), 1, &stream); COPY_VECTOR3(joint->position, unit.position); COPY_VECTOR3(joint->rotation, unit.rotation); COPY_VECTOR3(joint->position_lower_limit, unit.position_lower_limit); COPY_VECTOR3(joint->position_upper_limit, unit.position_upper_limit); COPY_VECTOR3(joint->rotation_lower_limit, unit.rotation_lower_limit); COPY_VECTOR3(joint->rotation_upper_limit, unit.rotation_upper_limit); COPY_VECTOR3(joint->position_stiffness, unit.position_stiffness); COPY_VECTOR3(joint->rotation_stiffness, unit.rotation_stiffness); *data_size = stream.data_point; }
bool disasmispossiblestring(uint addr) { unsigned char data[11]; memset(data, 0, sizeof(data)); if(!MemRead((void*)addr, data, sizeof(data) - 3, 0)) return false; uint test = 0; memcpy(&test, data, sizeof(uint)); if(MemIsValidReadPtr(test)) //imports/pointers return false; if(isasciistring(data, sizeof(data)) or isunicodestring(data, _countof(data))) return true; return false; }
FunctionPass::FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { // Zero values m_FunctionInfo = nullptr; m_FunctionInfoSize = 0; // This will only be valid if the address range is within a loaded module m_ModuleStart = ModBaseFromAddr(VirtualStart); if(m_ModuleStart != 0) { char modulePath[MAX_PATH]; memset(modulePath, 0, sizeof(modulePath)); ModPathFromAddr(m_ModuleStart, modulePath, ARRAYSIZE(modulePath)); HANDLE fileHandle; DWORD fileSize; HANDLE fileMapHandle; ULONG_PTR fileMapVa; if(StaticFileLoadW( StringUtils::Utf8ToUtf16(modulePath).c_str(), UE_ACCESS_READ, false, &fileHandle, &fileSize, &fileMapHandle, &fileMapVa)) { // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); m_FunctionInfoSize = (ULONG)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); // Unload the file StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); // Get a copy of the function table if(virtualOffset) { // Read the table into a buffer m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize); if(m_FunctionInfo) MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize); } } } }
int Pmd2BonePreparse( MEMORY_STREAM_PTR stream, PMD_DATA_INFO* info ) { uint16 size; if(MemRead(&size, sizeof(size), 1, stream) == 0 || size * PMD_BONE_UNIT_SIZE + stream->data_point > stream->data_size) { return FALSE; } info->bones_count = size; info->bones = &stream->buff_ptr[stream->data_point]; return MemSeek(stream, size * PMD_BONE_UNIT_SIZE, SEEK_CUR) == 0; }
static BOOL CALLBACK StackReadProcessMemoryProc64(HANDLE hProcess, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) { // Fix for 64-bit sizes SIZE_T bytesRead = 0; if(MemRead((duint)lpBaseAddress, lpBuffer, nSize, &bytesRead)) { if(lpNumberOfBytesRead) *lpNumberOfBytesRead = (DWORD)bytesRead; return true; } return false; }
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size) { _functionInfoData = nullptr; #ifdef _WIN64 // This will only be valid if the address range is within a loaded module _moduleBase = ModBaseFromAddr(base); if(exceptionDirectory && _moduleBase != 0) { char modulePath[MAX_PATH]; memset(modulePath, 0, sizeof(modulePath)); ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath)); HANDLE fileHandle; DWORD fileSize; HANDLE fileMapHandle; ULONG_PTR fileMapVa; if(StaticFileLoadW( StringUtils::Utf8ToUtf16(modulePath).c_str(), UE_ACCESS_READ, false, &fileHandle, &fileSize, &fileMapHandle, &fileMapVa)) { // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); _functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); // Unload the file StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); // Get a copy of the function table if(virtualOffset) { // Read the table into a buffer _functionInfoData = emalloc(_functionInfoSize); if(_functionInfoData) MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize); } } } #endif //_WIN64 }