#include #include #include #include #include #include "host.h" #include "textthread.h" #include "LunaHost.h" #include "Lang/Lang.h" #include "http.hpp" bool sendclipboarddata_i(const std::wstring &text, HWND hwnd) { if (!OpenClipboard((HWND)hwnd)) return false; HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (text.size() + 1) * sizeof(wchar_t)); memcpy(GlobalLock(hMem), text.c_str(), (text.size() + 1) * sizeof(wchar_t)); EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hMem); GlobalUnlock(hMem); CloseClipboard(); return true; } bool sendclipboarddata(const std::wstring &text, HWND hwnd) { for (int loop = 0; loop < 10; loop++) { auto succ = sendclipboarddata_i(text, hwnd); if (succ) return true; std::this_thread::sleep_for(std::chrono::milliseconds(50)); } return false; } void LunaHost::on_close() { hasstoped = true; savesettings(); delete configs; auto _attachedprocess = attachedprocess; for (auto pid : _attachedprocess) { Host::DetachProcess(pid); } if (_attachedprocess.size()) std::this_thread::sleep_for(std::chrono::milliseconds(100)); } void LunaHost::savesettings() { configs->set("ToClipboard", check_toclipboard); configs->set("ToClipboardSelection", check_toclipboard_selection); configs->set("AutoAttach", autoattach); configs->set("AutoAttach_SavedOnly", autoattach_savedonly); configs->set("flushDelay", TextThread::flushDelay); configs->set("filterRepetition", TextThread::filterRepetition); configs->set("maxBufferSize", TextThread::maxBufferSize); configs->set("maxHistorySize", TextThread::maxHistorySize); configs->set("defaultCodepage", Host::defaultCodepage); configs->set("autoattachexes", autoattachexes); configs->set("savedhookcontext", savedhookcontext); configs->set("DefaultFont2", WideStringToString(uifont.fontfamily)); configs->set("fontsize", uifont.fontsize); configs->set("font_italic", uifont.italic); configs->set("font_bold", uifont.bold); } void LunaHost::loadsettings() { uifont.italic = configs->get("font_italic", false); uifont.bold = configs->get("font_bold", false); uifont.fontsize = configs->get("fontsize", 14); uifont.fontfamily = StringToWideString(configs->get("DefaultFont2", WideStringToString(std::wstring(DefaultFont)))); check_toclipboard_selection = configs->get("ToClipboardSelection", false); check_toclipboard = configs->get("ToClipboard", false); autoattach = configs->get("AutoAttach", false); autoattach_savedonly = configs->get("AutoAttach_SavedOnly", true); TextThread::flushDelay = configs->get("flushDelay", TextThread::flushDelay); TextThread::filterRepetition = configs->get("filterRepetition", TextThread::filterRepetition); TextThread::maxBufferSize = configs->get("maxBufferSize", TextThread::maxBufferSize); TextThread::maxHistorySize = configs->get("maxHistorySize", TextThread::maxHistorySize); Host::defaultCodepage = configs->get("defaultCodepage", Host::defaultCodepage); autoattachexes = configs->get("autoattachexes", std::set{}); savedhookcontext = configs->get("savedhookcontext", decltype(savedhookcontext){}); } std::unordered_map> getprocesslist(); void LunaHost::doautoattach() { if (autoattach == false && autoattach_savedonly == false) return; if (autoattachexes.empty()) return; for (auto [pexe, pids] : getprocesslist()) { auto &&u8procname = WideStringToString(pexe); if (autoattachexes.find(u8procname) == autoattachexes.end()) continue; if (autoattach_savedonly && savedhookcontext.find(u8procname) == savedhookcontext.end()) continue; for (auto pid : pids) { if (userdetachedpids.find(pid) != userdetachedpids.end()) continue; if (attachedprocess.find(pid) == attachedprocess.end()) Host::InjectProcess(pid); } break; } } void LunaHost::on_proc_disconnect(DWORD pid) { attachedprocess.erase(pid); } void LunaHost::on_proc_connect(DWORD pid) { attachedprocess.insert(pid); if (auto pexe = getModuleFilename(pid)) { autoattachexes.insert(WideStringToString(pexe.value())); auto u8procname = WideStringToString(pexe.value()); if (savedhookcontext.find(u8procname) != savedhookcontext.end()) { std::string name = safequeryjson(savedhookcontext[u8procname], "name", std::string()); if (startWith(name, "UserHook")) { if (auto hp = HookCode::Parse(StringToWideString(savedhookcontext[u8procname]["hookcode"]))) Host::InsertHook(pid, hp.value()); } } } } bool queryversion(WORD *_1, WORD *_2, WORD *_3, WORD *_4) { wchar_t fileName[MAX_PATH]; GetModuleFileNameW(NULL, fileName, MAX_PATH); DWORD dwHandle; DWORD dwSize = GetFileVersionInfoSizeW(fileName, &dwHandle); if (dwSize == 0) { return false; } std::vector versionInfoBuffer(dwSize); if (!GetFileVersionInfoW(fileName, dwHandle, dwSize, versionInfoBuffer.data())) { return false; } VS_FIXEDFILEINFO *pFileInfo; UINT fileInfoSize; if (!VerQueryValueW(versionInfoBuffer.data(), L"\\", reinterpret_cast(&pFileInfo), &fileInfoSize)) { return false; } DWORD ms = pFileInfo->dwFileVersionMS; DWORD ls = pFileInfo->dwFileVersionLS; WORD majorVersion = HIWORD(ms); WORD minorVersion = LOWORD(ms); WORD buildNumber = HIWORD(ls); WORD revisionNumber = LOWORD(ls); *_1 = majorVersion; *_2 = minorVersion; *_3 = buildNumber; *_4 = revisionNumber; return true; } LunaHost::LunaHost() { configs = new confighelper; loadsettings(); setfont(uifont); btnshowsettionwindow = new button(this, BtnShowSettingWindow); g_selectprocessbutton = new button(this, BtnSelectProcess); // btnsavehook=new button(this,BtnSaveHook,10,10,10,10); // btnsavehook->onclick=std::bind(&LunaHost::btnsavehookscallback,this); btndetachall = new button(this, BtnDetach); btndetachall->onclick = [&]() { for (auto pid : attachedprocess) { Host::DetachProcess(pid); userdetachedpids.insert(pid); } }; g_hEdit_userhook = new lineedit(this); btnplugin = new button(this, BtnPlugin); plugins = new Pluginmanager(this); btnplugin->onclick = [&]() { if (pluginwindow == 0) pluginwindow = new Pluginwindow(this, plugins); pluginwindow->show(); }; g_hButton_insert = new button(this, BtnInsertUserHook); btnshowsettionwindow->onclick = [&]() { if (settingwindow == 0) settingwindow = new Settingwindow(this); settingwindow->show(); }; g_selectprocessbutton->onclick = [&]() { if (_processlistwindow == 0) _processlistwindow = new processlistwindow(this); _processlistwindow->show(); }; g_hButton_insert->onclick = [&]() { auto hp = HookCode::Parse(std::move(g_hEdit_userhook->text())); if (hp) { for (auto _ : attachedprocess) { Host::InsertHook(_, hp.value()); } } else { showtext(NotifyInvalidHookCode, false); } }; g_hListBox_listtext = new listview(this, false, false); g_hListBox_listtext->setheader({LIST_HOOK, LIST_TEXT}); g_hListBox_listtext->oncurrentchange = [&](int idx) { auto thread_p = g_hListBox_listtext->getdata(idx); std::wstring get; currentselect = thread_p; std::wstring copy = ((TextThread *)thread_p)->storage->c_str(); strReplace(copy, L"\n", L"\r\n"); showtext(copy, true); }; g_hListBox_listtext->on_menu = [&]() -> maybehavemenu { auto tt = (TextThread *)g_hListBox_listtext->getdata(g_hListBox_listtext->currentidx()); Menu menu; menu.add(MenuCopyHookCode, [&, tt]() { sendclipboarddata(tt->hp.hookcode, winId); }); menu.add_sep(); menu.add(MenuRemoveHook, [&, tt]() { Host::RemoveHook(tt->tp.processId, tt->tp.addr); }); menu.add(MenuDetachProcess, [&, tt]() { Host::DetachProcess(tt->tp.processId); userdetachedpids.insert(tt->tp.processId); }); menu.add_sep(); menu.add(MenuRemeberSelect, [&, tt]() { if(auto pexe=getModuleFilename(tt->tp.processId)) savedhookcontext[WideStringToString(pexe.value())]={ {"hookcode",WideStringToString(tt->hp.hookcode)}, {"ctx1",tt->tp.ctx}, {"ctx2",tt->tp.ctx2}, {"name",WideStringToString(tt->name)} }; }); menu.add(MenuForgetSelect, [&, tt]() { if(auto pexe=getModuleFilename(tt->tp.processId)) savedhookcontext.erase(WideStringToString(pexe.value())); }); return menu; }; g_showtexts = new multilineedit(this); g_showtexts->setreadonly(true); btnsearchhooks = new button(this, BtnSearchHook); btnsearchhooks->onclick = [&]() { if (hooksearchwindow == 0) hooksearchwindow = new Hooksearchwindow(this); hooksearchwindow->show(); }; Host::Start( std::bind(&LunaHost::on_proc_connect, this, std::placeholders::_1), std::bind(&LunaHost::on_proc_disconnect, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_create, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_delete, this, std::placeholders::_1), std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2)); mainlayout = new gridlayout(); mainlayout->addcontrol(g_selectprocessbutton, 0, 0); mainlayout->addcontrol(btndetachall, 0, 1); mainlayout->addcontrol(btnshowsettionwindow, 0, 2); mainlayout->addcontrol(btnplugin, 0, 3); mainlayout->addcontrol(g_hEdit_userhook, 1, 0, 1, 2); mainlayout->addcontrol(g_hButton_insert, 1, 2); mainlayout->addcontrol(btnsearchhooks, 1, 3); mainlayout->addcontrol(g_hListBox_listtext, 2, 0, 1, 4); mainlayout->addcontrol(g_showtexts, 3, 0, 1, 4); mainlayout->setfixedheigth(0, 30); mainlayout->setfixedheigth(1, 30); setlayout(mainlayout); setcentral(1200, 800); std::wstring title = WndLunaHostGui; settext(title); std::thread([&]() { //https://lunatranslator.xyz/Github/LunaHook/issues/14 std::wstring sel; while(1) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); if(check_toclipboard_selection) { auto _sel=g_showtexts->getsel(); if(_sel!=sel){ sel=_sel; sendclipboarddata(sel,winId); } } } }) .detach(); std::thread([&] { while(1){ doautoattach(); std::this_thread::sleep_for(std::chrono::seconds(2)); } }) .detach(); WORD _1, _2, _3, _4; WCHAR vs[32]; if (queryversion(&_1, &_2, &_3, &_4)) { wsprintf(vs, L" | %s v%d.%d.%d", VersionCurrent, _1, _2, _3); title += vs; settext(title); std::thread([&]() { if (HttpRequest httpRequest{ L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", L"lunatranslator.xyz", L"GET", L"/version_lunahook" }){ try{ auto resp=nlohmann::json::parse(WideStringToString(httpRequest.response)); std::string ver=resp["version"]; settext(text()+L" | "+VersionLatest+L" "+ StringToWideString(ver)); } catch(std::exception&e){} } }) .detach(); } } void LunaHost::on_text_recv_checkissaved(TextThread &thread) { if (auto exe = getModuleFilename(thread.tp.processId)) { auto exea = WideStringToString(exe.value()); if (savedhookcontext.find(exea) == savedhookcontext.end()) return; std::string hc = savedhookcontext[exea]["hookcode"]; uint64_t ctx1 = savedhookcontext[exea]["ctx1"]; uint64_t ctx2 = savedhookcontext[exea]["ctx2"]; if (((ctx1 & 0xffff) == (thread.tp.ctx & 0xffff)) && (ctx2 == thread.tp.ctx2) && (hc == WideStringToString(thread.hp.hookcode))) { for (int i = 0; i < g_hListBox_listtext->count(); i++) { auto handle = g_hListBox_listtext->getdata(i); if (handle == (LONG_PTR)&thread) { g_hListBox_listtext->setcurrent(i); break; } } } } } std::wstring sanitize(const std::wstring &s1) { std::wstring s = s1; s.erase(std::remove_if(s.begin(), s.end(), [](wchar_t ch) { return (ch >= 0xD800 && ch <= 0xDBFF) || (ch >= 0xDC00 && ch <= 0xDFFF); }), s.end()); return s; } void LunaHost::showtext(const std::wstring &text, bool clear) { auto output = sanitize(text); strReplace(output, L"\n", L"\r\n"); if (clear) { g_showtexts->settext(output); g_showtexts->scrolltoend(); } else { g_showtexts->scrolltoend(); g_showtexts->appendtext(output); } } void LunaHost::updatelisttext(const std::wstring &text, LONG_PTR data) { auto idx = g_hListBox_listtext->querydataidx(data); if (idx >= 0) { auto __output = sanitize(text); strReplace(__output, L"\n", L" "); if (__output.size() > 0x40) { __output = __output.substr(0, 0x40) + L"..."; } g_hListBox_listtext->settext(idx, 1, __output); } } bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output) { if (hasstoped) return true; if (!plugins->dispatch(thread, output)) return false; updatelisttext(output, (LONG_PTR)&thread); if (currentselect == (LONG_PTR)&thread) { showtext(output, false); } return true; } void LunaHost::on_thread_create(TextThread &thread) { wchar_t buff[65535]; swprintf_s(buff, L"%I64X:%s:%s:%I32X:%I64X:%I64X", thread.handle, thread.name.c_str(), thread.hp.hookcode, thread.tp.processId, thread.tp.ctx, thread.tp.ctx2); int index = g_hListBox_listtext->additem(buff, NULL); g_hListBox_listtext->setdata(index, (LONG_PTR)&thread); on_text_recv_checkissaved(thread); } void LunaHost::on_thread_delete(TextThread &thread) { if (currentselect == (LONG_PTR)&thread) currentselect = 0; int count = g_hListBox_listtext->count(); for (int i = 0; i < count; i++) { auto thread_p = g_hListBox_listtext->getdata(i); if (thread_p == (LONG_PTR)&thread) { g_hListBox_listtext->deleteitem(i); break; } } } Settingwindow::Settingwindow(LunaHost *host) : mainwindow(host) { int height = 30; int curry = 10; int space = 10; int labelwidth = 300; int spinwidth = 200; g_timeout = new spinbox(this, TextThread::flushDelay); g_codepage = new spinbox(this, Host::defaultCodepage); spinmaxbuffsize = new spinbox(this, TextThread::maxBufferSize); ; curry += height + space; spinmaxbuffsize->onvaluechange = [=](int v) { TextThread::maxBufferSize = v; }; spinmaxhistsize = new spinbox(this, TextThread::maxHistorySize); ; curry += height + space; spinmaxhistsize->onvaluechange = [=](int v) { TextThread::maxHistorySize = v; }; ckbfilterrepeat = new checkbox(this, LblFilterRepeat); ckbfilterrepeat->onclick = [=]() { TextThread::filterRepetition = ckbfilterrepeat->ischecked(); }; ckbfilterrepeat->setcheck(TextThread::filterRepetition); g_check_clipboard = new checkbox(this, BtnToClipboard); g_check_clipboard->onclick = [=]() { host->check_toclipboard = g_check_clipboard->ischecked(); }; g_check_clipboard->setcheck(host->check_toclipboard); // copyselect=new checkbox(this,COPYSELECTION); // copyselect->onclick=[=](){ // host->check_toclipboard_selection=copyselect->ischecked(); // }; // copyselect->setcheck(host->check_toclipboard_selection); autoattach = new checkbox(this, LblAutoAttach); autoattach->onclick = [=]() { host->autoattach = autoattach->ischecked(); }; autoattach->setcheck(host->autoattach); autoattach_so = new checkbox(this, LblAutoAttach_savedonly); autoattach_so->onclick = [=]() { host->autoattach_savedonly = autoattach_so->ischecked(); }; autoattach_so->setcheck(host->autoattach_savedonly); readonlycheck = new checkbox(this, BtnReadOnly); readonlycheck->onclick = [=]() { host->g_showtexts->setreadonly(readonlycheck->ischecked()); }; readonlycheck->setcheck(true); g_timeout->onvaluechange = [=](int v) { TextThread::flushDelay = v; }; g_codepage->onvaluechange = [=](int v) { if (IsValidCodePage(v)) { Host::defaultCodepage = v; } }; g_codepage->setminmax(0, CP_UTF8); showfont = new lineedit(this); showfont->settext(host->uifont.fontfamily); showfont->setreadonly(true); selectfont = new button(this, FONTSELECT); selectfont->onclick = [=]() { FontSelector(winId, host->uifont, [=](const Font &f) { host->uifont=f; showfont->settext(f.fontfamily); host->setfont(f); }); }; mainlayout = new gridlayout(); mainlayout->addcontrol(new label(this, LblFlushDelay), 0, 0); mainlayout->addcontrol(g_timeout, 0, 1); mainlayout->addcontrol(new label(this, LblCodePage), 1, 0); mainlayout->addcontrol(g_codepage, 1, 1); mainlayout->addcontrol(new label(this, LblMaxBuff), 2, 0); mainlayout->addcontrol(spinmaxbuffsize, 2, 1); mainlayout->addcontrol(new label(this, LblMaxHist), 3, 0); mainlayout->addcontrol(spinmaxhistsize, 3, 1); mainlayout->addcontrol(ckbfilterrepeat, 4, 0, 1, 2); mainlayout->addcontrol(g_check_clipboard, 5, 0, 1, 2); mainlayout->addcontrol(autoattach, 6, 0, 1, 2); mainlayout->addcontrol(autoattach_so, 7, 0, 1, 2); mainlayout->addcontrol(readonlycheck, 8, 0, 1, 2); mainlayout->addcontrol(showfont, 9, 1); mainlayout->addcontrol(selectfont, 9, 0); setlayout(mainlayout); setcentral(600, 500); settext(WndSetting); } void Pluginwindow::on_size(int w, int h) { listplugins->setgeo(10, 10, w - 20, h - 20); } void Pluginwindow::pluginrankmove(int moveoffset) { auto idx = listplugins->currentidx(); if (idx == -1) return; auto idx2 = idx + moveoffset; auto a = min(idx, idx2), b = max(idx, idx2); if (a < 0 || b >= listplugins->count()) return; pluginmanager->swaprank(a, b); auto pa = ((LPCWSTR)listplugins->getdata(a)); auto pb = ((LPCWSTR)listplugins->getdata(b)); listplugins->deleteitem(a); listplugins->insertitem(b, std::filesystem::path(pa).stem()); listplugins->setdata(b, (LONG_PTR)pa); } Pluginwindow::Pluginwindow(mainwindow *p, Pluginmanager *pl) : mainwindow(p), pluginmanager(pl) { static auto listadd = [&](const std::wstring &s) { auto idx = listplugins->additem(std::filesystem::path(s).stem()); auto _s = new wchar_t[s.size() + 1]; wcscpy(_s, s.c_str()); listplugins->setdata(idx, (LONG_PTR)_s); }; listplugins = new listbox(this); listplugins->on_menu = [&]() { Menu menu; menu.add(MenuAddPlugin, [&]() { if(auto f=pluginmanager->selectpluginfile()) switch (auto res=pluginmanager->addplugin(f.value())) { case addpluginresult::success: listadd(f.value()); break; default: std::map errorlog={ {addpluginresult::isnotaplugins,InvalidPlugin}, {addpluginresult::invaliddll,InvalidDll}, {addpluginresult::dumplicate,InvalidDump}, }; MessageBoxW(winId,errorlog[res],MsgError,0); } }); auto idx = listplugins->currentidx(); if (idx != -1) { menu.add(MenuRemovePlugin, [&, idx]() { pluginmanager->remove((LPCWSTR)listplugins->getdata(idx)); listplugins->deleteitem(idx); }); menu.add_sep(); menu.add(MenuPluginRankUp, std::bind(&Pluginwindow::pluginrankmove, this, -1)); menu.add(MenuPluginRankDown, std::bind(&Pluginwindow::pluginrankmove, this, 1)); menu.add_sep(); menu.add_checkable(MenuPluginEnable, pluginmanager->getenable(idx), [&, idx](bool check) { pluginmanager->setenable(idx,check); if(check) pluginmanager->load((LPCWSTR)listplugins->getdata(idx)); else pluginmanager->unload((LPCWSTR)listplugins->getdata(idx)); }); if (pluginmanager->getvisible_setable(idx)) menu.add_checkable(MenuPluginVisSetting, pluginmanager->getvisible(idx), [&, idx](bool check) { pluginmanager->setvisible(idx, check); }); } return menu; }; for (int i = 0; i < pluginmanager->count(); i++) { listadd(pluginmanager->getname(i)); } settext(WndPlugins); setcentral(500, 400); } void HooksearchText::call(std::set pids) { edittext->settext(L""); checkok->onclick = [&, pids]() { close(); auto cp = codepage->getcurr(); if (!IsValidCodePage(cp)) return; SearchParam sp = {}; sp.codepage = cp; wcsncpy_s(sp.text, edittext->text().c_str(), PATTERN_SIZE - 1); for (auto pid : pids) Host::FindHooks(pid, sp); }; show(); } HooksearchText::HooksearchText(mainwindow *p) : mainwindow(p) { codepage = new spinbox(this, Host::defaultCodepage); codepage->setminmax(0, CP_UTF8); edittext = new lineedit(this); checkok = new button(this, BtnOk); layout = new gridlayout(); layout->addcontrol(new label(this, HS_TEXT), 0, 0); layout->addcontrol(new label(this, HS_CODEPAGE), 1, 0); layout->addcontrol(edittext, 0, 1); layout->addcontrol(codepage, 1, 1); layout->addcontrol(checkok, 2, 1); setlayout(layout); setcentral(500, 200); } std::wstring tohex(BYTE *bs, int len) { std::wstring buffer; for (int i = 0; i < len; i += 1) { buffer.append(FormatString(L"%02hX ", bs[i])); } return buffer; } std::wstring addr2hex(uintptr_t addr) { return FormatString(L"%p", addr); } void realcallsearchhooks(std::set pids, std::wstring filter, SearchParam sp) { auto hooks = std::make_shared>(); try { for (auto processId : pids) Host::FindHooks(processId, sp, [hooks, filter](HookParam hp, std::wstring text) { std::wsmatch matches; if (std::regex_search(text, matches, std::wregex(filter))) { hooks->emplace_back(std::wstring(hp.hookcode) + L"=>" + text); } }); } catch (std::exception &e) { // std::wcout<size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size(); std::ofstream of; of.open("savehooks.txt"); for (auto line:*hooks) of<clear(); }) .detach(); } Hooksearchsetting::Hooksearchsetting(mainwindow *p) : mainwindow(p) { layout = new gridlayout(); SearchParam sp{}; spinduration = new spinbox(this, sp.searchTime); spinoffset = new spinbox(this, sp.offset); spincap = new spinbox(this, sp.maxRecords); spincodepage = new spinbox(this, Host::defaultCodepage); editpattern = new lineedit(this); editpattern->settext(tohex(sp.pattern, sp.length)); editmodule = new lineedit(this); editmaxaddr = new lineedit(this); editmaxaddr->settext(addr2hex(sp.maxAddress)); editminaddr = new lineedit(this); editminaddr->settext(addr2hex(sp.minAddress)); spinpadding = new spinbox(this, 0); editregex = new lineedit(this); start = new button(this, HS_START_HOOK_SEARCH); layout->addcontrol(new label(this, HS_SEARCH_PATTERN), 0, 0); layout->addcontrol(new label(this, HS_SEARCH_DURATION), 1, 0); layout->addcontrol(new label(this, HS_PATTERN_OFFSET), 2, 0); layout->addcontrol(new label(this, HS_MAX_HOOK_SEARCH_RECORDS), 3, 0); layout->addcontrol(new label(this, HS_CODEPAGE), 4, 0); layout->addcontrol(new label(this, HS_SEARCH_MODULE), 5, 0); layout->addcontrol(new label(this, HS_MIN_ADDRESS), 6, 0); layout->addcontrol(new label(this, HS_MAX_ADDRESS), 7, 0); layout->addcontrol(new label(this, HS_STRING_OFFSET), 8, 0); layout->addcontrol(new label(this, HS_HOOK_SEARCH_FILTER), 9, 0); layout->addcontrol(start, 10, 1); layout->addcontrol(editpattern, 0, 1); layout->addcontrol(spinduration, 1, 1); layout->addcontrol(spinoffset, 2, 1); layout->addcontrol(spincap, 3, 1); layout->addcontrol(spincodepage, 4, 1); layout->addcontrol(editmodule, 5, 1); layout->addcontrol(editminaddr, 6, 1); layout->addcontrol(editmaxaddr, 7, 1); layout->addcontrol(spinpadding, 8, 1); layout->addcontrol(editregex, 9, 1); setlayout(layout); setcentral(1000, 600); } std::vector hexStringToBytes(const std::wstring &hexString_) { auto hexString = hexString_; strReplace(hexString, L" ", L""); strReplace(hexString, L"??", FormatString(L"%02hX", XX)); std::vector bytes; if (hexString.length() % 2 != 0) { return {}; } for (int i = 0; i < hexString.size() / 2; i++) { auto byteValue = std::stoi(hexString.substr(i * 2, 2), nullptr, 16); bytes.push_back(byteValue); } return bytes; } void Hooksearchsetting::call(std::set pids, std::wstring reg) { if (pids.empty()) return; if (auto filename = getModuleFilename(*pids.begin())) editmodule->settext(std::filesystem::path(filename.value()).filename().wstring()); editregex->settext(reg); spincodepage->setcurr(Host::defaultCodepage); start->onclick = [&, pids]() { close(); SearchParam sp{}; sp.searchTime = spinduration->getcurr(); sp.offset = spinoffset->getcurr(); sp.maxRecords = spincap->getcurr(); sp.codepage = spincodepage->getcurr(); if (editpattern->text().find(L".") == std::wstring::npos) { auto hex = hexStringToBytes(editpattern->text()); memcpy(sp.pattern, hex.data(), hex.size()); sp.length = hex.size(); } else { wcsncpy_s(sp.exportModule, editpattern->text().c_str(), MAX_MODULE_SIZE - 1); sp.length = 1; } wcscpy(sp.boundaryModule, editmodule->text().c_str()); sp.minAddress = std::stoll(editminaddr->text(), nullptr, 16); sp.maxAddress = std::stoll(editmaxaddr->text(), nullptr, 16); sp.padding = spinpadding->getcurr(); realcallsearchhooks(pids, editregex->text(), sp); }; show(); } Hooksearchwindow::Hooksearchwindow(LunaHost *host) : mainwindow(host) { cjkcheck = new checkbox(this, SEARCH_CJK); hs_default = new button(this, HS_START_HOOK_SEARCH); hs_text = new button(this, HS_SEARCH_FOR_TEXT); hs_user = new button(this, HS_SETTINGS); layout = new gridlayout(); layout->addcontrol(cjkcheck, 0, 0, 1, 3); layout->addcontrol(hs_default, 1, 0); layout->addcontrol(hs_text, 1, 1); layout->addcontrol(hs_user, 1, 2); setlayout(layout); settext(BtnSearchHook); setcentral(800, 200); auto dohooksearchdispatch = [&, host](int type) { close(); if (type == 1) { if (hooksearchText == 0) hooksearchText = new HooksearchText(this); hooksearchText->call(host->attachedprocess); return; } auto filter = (cjkcheck->ischecked() ? L"[\\u3000-\\ua000]{4,}" : L"[\\u0020-\\u1000]{4,}"); if (type == 0) { SearchParam sp = {}; sp.codepage = Host::defaultCodepage; sp.length = 0; realcallsearchhooks(host->attachedprocess, filter, sp); } else if (type == 2) { if (hooksearchsetting == 0) hooksearchsetting = new Hooksearchsetting(this); hooksearchsetting->call(host->attachedprocess, filter); return; } }; hs_default->onclick = std::bind(dohooksearchdispatch, 0); hs_text->onclick = std::bind(dohooksearchdispatch, 1); hs_user->onclick = std::bind(dohooksearchdispatch, 2); }