mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-27 13:44:11 +08:00
819 lines
27 KiB
C++
819 lines
27 KiB
C++
|
||
#include <CommCtrl.h>
|
||
#include <TlHelp32.h>
|
||
#include<stdio.h>
|
||
#include<thread>
|
||
#include<fstream>
|
||
#include"host.h"
|
||
#include"hookcode.h"
|
||
#include"textthread.h"
|
||
#include"LunaHost.h"
|
||
#include"Lang/Lang.h"
|
||
#include"http.hpp"
|
||
auto gmf=[&](DWORD processId)->std::optional<std::wstring>{
|
||
//见鬼了,GetModuleFileName找不到标识符
|
||
std::vector<wchar_t> buffer(MAX_PATH);
|
||
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, processId))
|
||
if (GetModuleFileNameExW(process, 0, buffer.data(), MAX_PATH)) return buffer.data();
|
||
return {};
|
||
};
|
||
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(){
|
||
savesettings();
|
||
delete configs;
|
||
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);
|
||
}
|
||
void LunaHost::loadsettings(){
|
||
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);
|
||
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){
|
||
uint64_t handle = g_hListBox_listtext->getdata(idx);
|
||
std::wstring get;
|
||
for(auto& _:savetext.at(handle)){
|
||
get+=_;
|
||
get+=L"\n";
|
||
}
|
||
currentselect=handle;
|
||
showtext(get,true);
|
||
};
|
||
g_hListBox_listtext->on_menu=[&]()->maybehavemenu{
|
||
auto handle = g_hListBox_listtext->getdata(g_hListBox_listtext->currentidx());
|
||
auto tt=Host::GetThread(handle);
|
||
if(!tt)return {};
|
||
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=gmf(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=gmf(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/HIllya51/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/HIllya51/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(onceautoselectthread.find(thread.handle)!=onceautoselectthread.end())return;
|
||
|
||
onceautoselectthread.insert(thread.handle);
|
||
|
||
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==thread.handle)
|
||
{
|
||
g_hListBox_listtext->setcurrent(i);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
void LunaHost::showtext(const std::wstring&text,bool clear){
|
||
auto output=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=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){
|
||
std::lock_guard _(settextmutex);
|
||
on_text_recv_checkissaved(thread);
|
||
if(!plugins->dispatch(thread,output))return false;
|
||
|
||
updatelisttext(output,thread.handle);
|
||
|
||
savetext.at(thread.handle).push_back(output);
|
||
if(currentselect==thread.handle){
|
||
showtext(output,false);
|
||
}
|
||
return true;
|
||
}
|
||
void LunaHost::on_thread_create(TextThread& thread){
|
||
wchar_t buff[65535];
|
||
swprintf_s(buff,L"%s:%s:%I32X:%I64X:%I64X",
|
||
thread.name.c_str(),
|
||
thread.hp.hookcode,
|
||
thread.tp.processId,
|
||
thread.tp.ctx,
|
||
thread.tp.ctx2
|
||
);
|
||
savetext.insert({thread.handle,{}});
|
||
int index=g_hListBox_listtext->additem(buff,NULL);
|
||
g_hListBox_listtext->setdata(index,thread.handle);
|
||
}
|
||
void LunaHost::on_thread_delete(TextThread& thread){
|
||
int count = g_hListBox_listtext->count();
|
||
for (int i = 0; i < count; i++) {
|
||
uint64_t handle = g_hListBox_listtext->getdata(i);
|
||
|
||
if (handle== thread.handle) {
|
||
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);
|
||
|
||
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(copyselect,9,0,1,2);
|
||
|
||
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));
|
||
});
|
||
}
|
||
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=gmf(*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);
|
||
} |