LunaHook-mirror/LunaHost/GUI/LunaHost.cpp
恍兮惚兮 49da30b2b3 link
2024-07-07 19:19:27 +08:00

833 lines
28 KiB
C++

#include <CommCtrl.h>
#include <TlHelp32.h>
#include<stdio.h>
#include<thread>
#include<fstream>
#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("DefaultFont",defaultFont);
}
void LunaHost::loadsettings(){
defaultFont=configs->get("DefaultFont",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<std::string>{});
savedhookcontext=configs->get("savedhookcontext",decltype(savedhookcontext){});
}
std::unordered_map<std::wstring,std::vector<int>> 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<char> versionInfoBuffer(dwSize);
if (!GetFileVersionInfoW(fileName, dwHandle, dwSize, versionInfoBuffer.data()))
{
return false;
}
VS_FIXEDFILEINFO *pFileInfo;
UINT fileInfoSize;
if (!VerQueryValueW(versionInfoBuffer.data(), L"\\", reinterpret_cast<LPVOID *>(&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(25,defaultFont.c_str());
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://github.com/test123456654321/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"api.github.com",
L"GET",
L"/repos/test123456654321/LunaHook/releases/latest"
}){
try{
auto resp=nlohmann::json::parse(WideStringToString(httpRequest.response));
std::string ver=resp["tag_name"];
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->defaultFont);
showfont->setreadonly(true);
selectfont=new button(this,FONTSELECT);
selectfont->onclick=[=](){
FontSelector(winId,host->defaultFont, [=](const std::wstring& _t){
showfont->settext(_t);
host->defaultFont=_t;
host->setfont(25,_t.c_str());
});
};
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<addpluginresult,LPCWSTR> 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<DWORD>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<DWORD>pids,std::wstring filter,SearchParam sp){
auto hooks = std::make_shared<std::vector<std::wstring>>();
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<<e.what();
return;
}
std::thread([hooks]
{
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
std::ofstream of;
of.open("savehooks.txt");
for (auto line:*hooks) of<<WideStringToString(line)<<"\n";
of.close();
hooks->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<BYTE> hexStringToBytes(const std::wstring& hexString_) {
auto hexString=hexString_;
strReplace(hexString,L" ",L"");
strReplace(hexString,L"??",FormatString(L"%02hX",XX));
std::vector<BYTE> 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<DWORD>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);
}