mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-26 21:24:12 +08:00
833 lines
28 KiB
C++
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/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(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);
|
|
} |