DWORD ReflectiveLoaderOffset(DWORD BaseAddress){ PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pImageHeader; PIMAGE_EXPORT_DIRECTORY PExportDirectory; //DWORD RDLLAddress; pDosHeader = (PIMAGE_DOS_HEADER)BaseAddress; pImageHeader = (PIMAGE_NT_HEADERS)(BaseAddress + pDosHeader->e_lfanew); DWORD ExportRVA = pImageHeader->OptionalHeader.DataDirectory[0].VirtualAddress; PExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(RVAToOffset(pImageHeader,ExportRVA)+BaseAddress); PDWORD ExportFunctions = (PDWORD)(RVAToOffset(pImageHeader, PExportDirectory->AddressOfFunctions) + BaseAddress); PDWORD ExportNames = (PDWORD)(RVAToOffset(pImageHeader, PExportDirectory->AddressOfNames) + BaseAddress); PWORD ExportOrdinals = (PWORD)(RVAToOffset(pImageHeader, PExportDirectory->AddressOfNameOrdinals) + BaseAddress); char *check = nullptr; char *tempPointer = nullptr; bool gotcha = false; DWORD address = 0; for (DWORD i =0; i<PExportDirectory->NumberOfFunctions; i++) { //std::cout << (char*)(DWORD*)RVAToOffset(pImageHeader,ExportNames[i]) + BaseAddress << std::endl; //std::cout << (PDWORD)RVAToOffset(pImageHeader,ExportFunctions[ExportOrdinals[i]]) + BaseAddress << std::endl; check = ((char*)(DWORD*)RVAToOffset(pImageHeader,ExportNames[i]) + BaseAddress); tempPointer = strstr(check,"ReflectiveLoader"); if(tempPointer != nullptr && check != nullptr) { gotcha = true; address = (DWORD)RVAToOffset(pImageHeader,ExportFunctions[ExportOrdinals[i]]); break; } } if (gotcha) { dprintf(L"[*] ReflectiveDll function offset found: 0x%08x\n", address); return address; } else return 0x153e; //hardcoded from original metsrv.dll... we have not tested these functions thoroughly yet. };
ulong GetFunctionOffset(std::string dllPath, std::string functionName) { // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx // offset to PE header is always at 0x3C // PE header starts with "PE\0\0" = 0x50 0x45 0x00 0x00 // Followed by 2-byte machine type field ifstream inFile(dllPath.c_str(), ifstream::in | ifstream::binary); std::streamoff size = 0; if (inFile.is_open()) { char* oData = 0; inFile.seekg(0, ios::end); size = inFile.tellg(); inFile.seekg(0, ios::beg); oData = new char[size + 1]; inFile.read(oData, size); oData[size] = '\0'; //IMAGE_DOS_HEADER dosHeader = ReadStruct<IMAGE_DOS_HEADER>(br); uint offset = read<uint>(oData, 0x3c, NULL); uint cPosition; uint pHead = read<uint>(oData, offset, &cPosition); if (pHead != PE::IMAGE_NT_SIGNATURE) // "PE\0\0" little-endian { // Not a valid portable executable return 0; } //IMAGE_FILE_HEADER fileHeader = IMAGE_FILE_HEADER.FromStream(br); IMAGE_FILE_HEADER fileHeader = read<IMAGE_FILE_HEADER>(oData, cPosition, &cPosition); ushort machineType = fileHeader.Machine; bool is64Bit = false; if (machineType != (ushort)UNKNOWN) { if (machineType == IA64 || machineType == AMD64) { is64Bit = true; } } else { return 0; } IMAGE_DATA_DIRECTORY exportDirectory; if (!is64Bit) { //IMAGE_OPTIONAL_HEADER optionalHeader = IMAGE_OPTIONAL_HEADER.FromStream(br); IMAGE_OPTIONAL_HEADER optionalHeader = read<IMAGE_OPTIONAL_HEADER>(oData, cPosition, &cPosition); exportDirectory = optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; } else { IMAGE_OPTIONAL_HEADER64 optionalHeader = read<IMAGE_OPTIONAL_HEADER64>(oData, cPosition, &cPosition); exportDirectory = optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; } //UInt32 exportPtr = optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; //fs.Seek(exportPtr, SeekOrigin.Begin); // should now be at the .export section! uint nSec = fileHeader.NumberOfSections; IMAGE_SECTION_HEADER *sec = new IMAGE_SECTION_HEADER[nSec]; for (uint i = 0; i < nSec; i++) { sec[i] = read<IMAGE_SECTION_HEADER>(oData, cPosition, &cPosition); } // = optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; uint exportOffset = RVAToOffset(exportDirectory.VirtualAddress, sec, nSec); if (exportOffset > 0) { cPosition = exportOffset; IMAGE_EXPORT_DIRECTORY exports = read<IMAGE_EXPORT_DIRECTORY>(oData, cPosition, &cPosition); uint nameOffset = RVAToOffset(exports.AddressOfNames, sec, nSec); uint funcOffset = RVAToOffset(exports.AddressOfFunctions, sec, nSec); uint ordinalOffset = RVAToOffset(exports.AddressOfNameOrdinals, sec, nSec); uint length = min(exports.NumberOfFunctions, exports.NumberOfNames); vector<string> names; vector<uint> addresses; vector<uint> ordinals; // Read in all named-function names: cPosition = nameOffset; for (uint i = 0; i < length; i++) { uint stringLocation = read<uint>(oData, cPosition, &cPosition); uint theStringStart = RVAToOffset(stringLocation, sec, nSec); cPosition = theStringStart; names.push_back(&oData[cPosition]); cPosition = nameOffset + (i + 1) * 4; } // Read in all named-function offsets: cPosition = funcOffset; for (uint i = 0; i < length; i++) { addresses.push_back(read<uint>(oData, cPosition, &cPosition)); } // Read in all named-function ordinals cPosition = ordinalOffset; for (uint i = 0; i < length; i++) { ordinals.push_back((uint)(read<ushort>(oData, cPosition, &cPosition) + (exports.Base))); uint ord = ordinals[i] - exports.Base; if (ord >= 0 && ord < length) { string name = names[i]; ulong address = addresses[ord]; if (name.compare(functionName) == 0){ return address; } //printf("%s: %d\n", name.c_str(), address); } } } } return 0; }
unsigned long long MACHFile::getEntryPointOffset() { return RVAToOffset(getEntryPoint()); }