void dpLoader::unloadImpl( dpBinary *bin ) { m_binaries.erase(std::find(m_binaries.begin(), m_binaries.end(), bin)); bin->callHandler(dpE_OnUnload); std::string path = bin->getPath(); delete bin; dpPrintInfo("unloaded \"%s\"\n", path.c_str()); }
void dpPatcher::unpatchImpl(const dpPatchData &pi) { if(!dpIsValidMemory(pi.target->address)) { return; } DWORD old; ::VirtualProtect(pi.target->address, 32, PAGE_EXECUTE_READWRITE, &old); dpCopyInstructions(pi.target->address, pi.unpatched, pi.unpatched_size); ::VirtualProtect(pi.target->address, 32, old, &old); m_talloc.deallocate(pi.unpatched); m_talloc.deallocate(pi.trampoline); if((dpGetConfig().log_flags&dpE_LogInfo)!=0) { char demangled[512]; dpDemangleNameOnly(pi.target->name, demangled, sizeof(demangled)); dpPrintInfo("unpatch 0x%p (\"%s\" : \"%s\")\n", pi.target->address, demangled, pi.target->name); } }
bool dpLoader::link() { dpBuilder::ScopedPreloadLock pl(dpGetBuilder()); if(m_onload_queue.empty()) { return true; } bool ret = true; eachBinaries([&](dpBinary *bin){ if(!bin->link()) { ret=false; } }); if((dpGetConfig().sys_flags&dpE_SysDelayedLink)==0) { if(ret) { dpPrintInfo("link succeeded\n"); } else { dpPrintError("link error\n"); ::DebugBreak(); } } // 有効にされていれば dllexport な関数を自動的に patch if((dpGetConfig().sys_flags&dpE_SysPatchExports)!=0) { dpEach(m_onload_queue, [&](dpBinary *b){ b->eachSymbols([&](dpSymbol *sym){ if(dpIsExportFunction(sym->flags)) { sym->partialLink(); dpGetPatcher()->patch(findHostSymbolByName(sym->name), sym); } }); }); } // OnLoad があれば呼ぶ dpEach(m_onload_queue, [&](dpBinary *b){ b->callHandler(dpE_OnLoad); }); m_onload_queue.clear(); return ret; }
void dpPatcher::patchImpl(dpPatchData &pi) { // 元コードの退避先 BYTE *hook = (BYTE*)pi.hook->address; BYTE *target = (BYTE*)pi.target->address; BYTE *unpatched = (BYTE*)m_talloc.allocate(target); DWORD old; ::VirtualProtect(target, 32, PAGE_EXECUTE_READWRITE, &old); HANDLE proc = ::GetCurrentProcess(); // 元のコードをコピー & 最後にコピー本へ jmp するコードを付加 (==これを call すれば上書き前の動作をするハズ) size_t stab_size = dpCopyInstructions(unpatched, target, 5); dpAddJumpInstruction(unpatched+stab_size, target+stab_size); // 距離が 32bit に収まらない場合、長距離 jmp で飛ぶコードを挟む。 // (長距離 jmp は 14byte 必要なので直接書き込もうとすると容量が足りない可能性が出てくる) DWORD_PTR dwDistance = hook < target ? target - hook : hook - target; if(dwDistance > 0x7fff0000) { BYTE *trampoline = (BYTE*)m_talloc.allocate(target); dpAddJumpInstruction(trampoline, hook); dpAddJumpInstruction(target, trampoline); ::FlushInstructionCache(proc, trampoline, 32); ::FlushInstructionCache(proc, target, 32); pi.trampoline = trampoline; } else { dpAddJumpInstruction(target, hook); ::FlushInstructionCache(proc, target, 32); } ::VirtualProtect(target, 32, old, &old); pi.unpatched = unpatched; pi.unpatched_size = stab_size; if((dpGetConfig().log_flags&dpE_LogInfo)!=0) { // たぶん demangle はそこそこでかい処理なので early out char demangled[512]; dpDemangleNameOnly(pi.target->name, demangled, sizeof(demangled)); dpPrintInfo("patch 0x%p -> 0x%p (\"%s\" : \"%s\")\n", pi.target->address, pi.hook->address, demangled, pi.target->name); } }
BinaryType* dpLoader::loadBinaryImpl(const char *path) { dpBuilder::ScopedPreloadLock pl(dpGetBuilder()); BinaryType *old = static_cast<BinaryType*>(findBinary(path)); if(old) { dpTime t = dpGetMTime(path); if(t<=old->getLastModifiedTime()) { return old; } } BinaryType *ret = new BinaryType(m_context); if(ret->loadFile(path)) { if(old) { unloadImpl(old); } m_binaries.push_back(ret); addOnLoadList(ret); dpPrintInfo("loaded \"%s\"\n", ret->getPath()); } else { delete ret; ret = nullptr; } return ret; }