dpAPI bool dpInitialize(const dpConfig &conf) { if(!g_dpDefaultContext) { DWORD opt = ::SymGetOptions(); opt |= SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES; opt &= ~SYMOPT_UNDNAME; ::SymSetOptions(opt); ::SymInitialize(::GetCurrentProcess(), NULL, TRUE); dpConfig &g_dpConfig = dpGetConfig(); g_dpConfig = conf; g_dpConfig.starttime = dpGetSystemTime(); dpConfigFile cf; bool config_loaded = false; if((conf.sys_flags&dpE_SysLoadConfig)!=0 && (conf.configfile ? cf.load(conf.configfile) : cf.load())) { config_loaded = true; if(cf.log_flags!=-1) { g_dpConfig.log_flags=cf.log_flags; } if(cf.sys_flags!=-1) { g_dpConfig.sys_flags=cf.sys_flags; } if(cf.vc_ver!=-1) { g_dpConfig.vc_ver=cf.vc_ver; } } g_dpDefaultContext = new dpContext(); if(config_loaded) { if(!cf.loads.empty()) { dpEach(cf.loads, [](const std::string &path){ dpLoad(path.c_str()); }); dpLink(); } dpEach(cf.source_paths, [](const std::string &v){ dpAddSourcePath(v.c_str()); }); dpEach(cf.module_paths, [](const std::string &v){ dpAddModulePath(v.c_str()); }); dpEach(cf.preload_paths, [](const std::string &v){ dpAddPreloadPath(v.c_str()); }); dpEach(cf.msbuild_commands, [](const std::string &v){ dpAddMSBuildCommand(v.c_str()); }); dpEach(cf.build_commands, [](const std::string &v){ dpAddBuildCommand(v.c_str()); }); dpEach(cf.force_host_symbol_patterns, [](const std::string &v){ dpAddForceHostSymbolPattern(v.c_str()); }); if(!cf.source_paths.empty() && (!cf.msbuild_commands.empty() || !cf.build_commands.empty())) { dpStartAutoBuild(); } if(!cf.preload_paths.empty()) { dpStartPreload(); } } if((g_dpConfig.sys_flags & dpE_SysOpenConsole)!=0) { ::AllocConsole(); } if((g_dpConfig.sys_flags & dpE_SysRunCommunicator)!=0) { #ifdef dpWithNetwork dpInitializeNetwork(); #endif // dpWithNetwork bool auto_flush = (g_dpConfig.sys_flags & dpE_SysCommunicatorAutoFlush)!=0; g_dpDefaultContext->runCommunicator(g_dpConfig.communicator_port, auto_flush); } return true; } return false; }
void dpPrintDetail(const char* fmt, ...) { if((dpGetConfig().log_flags&dpE_LogDetail)==0) { return; } std::string format = std::string("dp detail: ")+fmt; va_list vl; va_start(vl, fmt); dpPrintV(format.c_str(), vl); va_end(vl); }
void dpPrintError(const char* fmt, ...) { if((dpGetConfig().log_flags&dpE_LogError)==0) { return; } std::string format = std::string("dp error: ")+fmt; // OutputDebugStringA() は超遅いので dpPrint() 2 回呼ぶよりこうした方がまだ速い va_list vl; va_start(vl, fmt); dpPrintV(format.c_str(), vl); va_end(vl); }
dpAPI bool dpFinalize() { if(g_dpDefaultContext) { delete g_dpDefaultContext; g_dpDefaultContext = nullptr; if((dpGetConfig().sys_flags & dpE_SysOpenConsole)!=0) { ::FreeConsole(); } return true; } return false; }
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::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); } }
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); } }