This commit is contained in:
恍兮惚兮 2024-03-28 19:24:07 +08:00
parent 6f3bc497ab
commit 6e011c5780
8 changed files with 326 additions and 30 deletions

View File

@ -48,6 +48,7 @@
#define BtnToClipboard L"Copy To Clipboard"
#define BtnReadOnly L"Text box Read only"
#define BtnInsertUserHook L"Insert UserHook"
#define BtnSearchHook L"Search for hooks"
#define BtnPlugin L"Plugins"
#define LblFlushDelay L"Flush delay"
#define LblFilterRepeat L"Filter repetition"
@ -70,4 +71,20 @@
#define LblPluginNotify L"Qt Plugins Will be Loaded at Start Only."
#define LblPluginRemove L"Remove Plugins Will be Useful after Restart."
#define InvalidPlugin L"Invalid Plugin!"
#define MsgError L"Error"
#define MsgError L"Error"
#define SEARCH_CJK L"Search for Chinese/Japanese/Korean"
#define HS_SETTINGS L"Settings"
#define BtnOk L"OK"
#define HS_START_HOOK_SEARCH L"Start hook search"
#define HS_SEARCH_PATTERN L"Search pattern (hex byte array)"
#define HS_SEARCH_DURATION L"Search duration (ms)"
#define HS_SEARCH_MODULE L"Search within module"
#define HS_PATTERN_OFFSET L"Offset from pattern start"
#define HS_MAX_HOOK_SEARCH_RECORDS L"Search result cap"
#define HS_MIN_ADDRESS L"Minimum address (hex)"
#define HS_MAX_ADDRESS L"Maximum address (hex)"
#define HS_STRING_OFFSET L"String offset (hex)"
#define HS_HOOK_SEARCH_FILTER L"Results must match this regex"
#define HS_TEXT L"Text"
#define HS_CODEPAGE L"Codepage"
#define HS_SEARCH_FOR_TEXT L"Search for specific text"

View File

@ -48,6 +48,7 @@
#define BtnToClipboard L"复制到剪贴板"
#define BtnReadOnly L"文本框只读"
#define BtnInsertUserHook L"插入特殊码"
#define BtnSearchHook L"搜索钩子"
#define BtnPlugin L"插件"
#define LblFlushDelay L"刷新延迟"
#define LblFilterRepeat L"过滤重复文本"
@ -70,4 +71,20 @@
#define LblPluginNotify L"依赖于Qt的插件仅会在启动时载入。"
#define LblPluginRemove L"移除插件要在重启后生效。"
#define InvalidPlugin L"插件无效!"
#define MsgError L"错误"
#define MsgError L"错误"
#define SEARCH_CJK L"搜索中文/日文/韩文"
#define HS_SETTINGS L"设置"
#define BtnOk L"确定"
#define HS_START_HOOK_SEARCH L"开始搜索钩子"
#define HS_SEARCH_PATTERN L"搜索匹配特征 (hex byte array)"
#define HS_SEARCH_DURATION L"搜索持续时间 (ms)"
#define HS_SEARCH_MODULE L"搜索指定模块"
#define HS_PATTERN_OFFSET L"相对于特征地址的偏移值"
#define HS_MAX_HOOK_SEARCH_RECORDS L"搜索结果达到上限"
#define HS_MIN_ADDRESS L"起始地址 (hex)"
#define HS_MAX_ADDRESS L"结束地址 (hex)"
#define HS_STRING_OFFSET L"字符串偏移值 (hex)"
#define HS_HOOK_SEARCH_FILTER L"结果必须匹配的正则表达式"
#define HS_TEXT L"文本"
#define HS_CODEPAGE L"代码页"
#define HS_SEARCH_FOR_TEXT L"搜索指定文本"

View File

@ -1,4 +1,4 @@
add_executable(LunaHost confighelper.cpp controls.cpp main.cpp processlistwindow.cpp LunaHost.cpp window.cpp luna.rc pluginmanager.cpp Plugin/pluginexample.cpp app.manifest)
add_executable(LunaHost WIN32 confighelper.cpp controls.cpp main.cpp processlistwindow.cpp LunaHost.cpp window.cpp luna.rc pluginmanager.cpp Plugin/pluginexample.cpp app.manifest)
target_precompile_headers(LunaHost REUSE_FROM pch)
set_target_properties(LunaHost PROPERTIES OUTPUT_NAME "LunaHost${bitappendix}")
target_link_libraries(LunaHost comctl32 pch host ${YY_Thunks_for_WinXP})

View File

@ -9,6 +9,13 @@
#include"textthread.h"
#include"LunaHost.h"
#include"Lang/Lang.h"
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 {};
};
void LunaHost::toclipboard(std::wstring& sentence){
for (int loop = 0; loop < 10; loop++) {
@ -198,15 +205,6 @@ LunaHost::LunaHost(){
case IDM_FORGET_SELECTION:
case IDM_REMEMBER_SELECTION:
{
std::vector<wchar_t> buffer(MAX_PATH);
auto gmf=[&](DWORD processId)->std::optional<std::wstring>{
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 {};
};
//见鬼了GetModuleFileName找不到标识符
if(auto pexe=gmf(tt->tp.processId))
{
@ -231,7 +229,13 @@ LunaHost::LunaHost(){
};
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),
[&](DWORD pid) {
@ -247,8 +251,9 @@ LunaHost::LunaHost(){
mainlayout->addcontrol(btndetachall,0,1);
mainlayout->addcontrol(btnshowsettionwindow,0,2);
mainlayout->addcontrol(btnplugin,0,3);
mainlayout->addcontrol(g_hEdit_userhook,1,0,1,3);
mainlayout->addcontrol(g_hButton_insert,1,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);
@ -332,28 +337,25 @@ void LunaHost::on_thread_delete(TextThread& thread){
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,std::to_wstring(TextThread::flushDelay)) ;
g_timeout = new spinbox(this,TextThread::flushDelay) ;
g_codepage = new spinbox(this,std::to_wstring(Host::defaultCodepage)) ;
g_codepage = new spinbox(this,Host::defaultCodepage) ;
spinmaxbuffsize = new spinbox(this,std::to_wstring(TextThread::maxBufferSize)) ;
spinmaxbuffsize = new spinbox(this,TextThread::maxBufferSize);
;curry+=height+space;
spinmaxbuffsize->onvaluechange=[=](int v){
TextThread::maxBufferSize=v;
};
spinmaxbuffsize->setminmax(0,0x7fffffff);
spinmaxhistsize = new spinbox(this,std::to_wstring(TextThread::maxHistorySize)) ;
spinmaxhistsize = new spinbox(this,TextThread::maxHistorySize) ;
;curry+=height+space;
spinmaxhistsize->onvaluechange=[=](int v){
TextThread::maxHistorySize=v;
};
spinmaxhistsize->setminmax(0,0x7fffffff);
ckbfilterrepeat=new checkbox(this,LblFilterRepeat);
ckbfilterrepeat->onclick=[=](){
@ -389,7 +391,7 @@ Settingwindow::Settingwindow(LunaHost* host):mainwindow(host){
g_timeout->onvaluechange=[=](int v){
TextThread::flushDelay=v;
};
g_timeout->setminmax(0,9999);
g_codepage->onvaluechange=[=](int v){
if(IsValidCodePage(v)){
Host::defaultCodepage= v;
@ -496,4 +498,223 @@ Pluginwindow::Pluginwindow(mainwindow*p,Pluginmanager* pl):mainwindow(p){
}
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);
wprintf(sp.text);
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_SEARCH_FOR_TEXT);
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);
}

View File

@ -38,11 +38,45 @@ public:
processlistwindow(mainwindow* parent=0);
void on_show();
};
class HooksearchText:public mainwindow{
gridlayout* layout;
lineedit* edittext;
button* checkok;
spinbox* codepage;
public:
HooksearchText(mainwindow*);
void call(std::set<DWORD>pids);
};
class Hooksearchsetting:public mainwindow{
gridlayout* layout;
spinbox* spinduration;
spinbox* spinoffset;
spinbox* spincap;
spinbox* spincodepage;
lineedit* editpattern;
lineedit* editmodule;
lineedit* editmaxaddr;
lineedit* editminaddr;
spinbox* spinpadding;
lineedit* editregex;
button* start;
public:
Hooksearchsetting(mainwindow*);
void call(std::set<DWORD>pids,std::wstring);
};
class Hooksearchwindow:public mainwindow{
checkbox* cjkcheck;
button* hs_default,*hs_text,*hs_user;
gridlayout* layout;
Hooksearchsetting* hooksearchsetting=0;
HooksearchText* hooksearchText=0;
public:
Hooksearchwindow(LunaHost* parent);
};
class LunaHost:public mainwindow{
Pluginwindow* pluginwindow=0;
std::map<int64_t,std::vector<std::wstring>>savetext;
std::set<int>attachedprocess;
std::set<DWORD>attachedprocess;
std::mutex settextmutex;
lineedit* g_hEdit_userhook;
gridlayout* mainlayout;
@ -52,12 +86,14 @@ class LunaHost:public mainwindow{
multilineedit* g_showtexts;
button* g_selectprocessbutton;
button* btndetachall;
button* btnsearchhooks;
button* btnshowsettionwindow;
//button* btnsavehook;
void toclipboard(std::wstring& sentence);
processlistwindow *_processlistwindow=0;
Settingwindow *settingwindow=0;
Pluginmanager* plugins;
Hooksearchwindow * hooksearchwindow=0;
bool on_text_recv(TextThread& thread, std::wstring& sentence);
void on_text_recv_checkissaved(TextThread& thread);
void on_thread_create(TextThread& thread);
@ -76,7 +112,7 @@ public:
void on_close();
LunaHost();
friend class Settingwindow;
friend class processlistwindow;
friend class Hooksearchwindow;
private:
void loadsettings();
void savesettings();

View File

@ -30,8 +30,11 @@ checkbox::checkbox(mainwindow* parent,const std::wstring& text):button(parent)
void checkbox::setcheck(bool b){
SendMessage(winId, BM_SETCHECK, (WPARAM)BST_CHECKED*b, 0);
}
spinbox::spinbox(mainwindow* parent,const std::wstring& text):control(parent){
winId=CreateWindowEx(0, L"EDIT", text.c_str(), WS_CHILD | WS_VISIBLE | WS_BORDER|ES_NUMBER ,
int spinbox::getcurr(){
return SendMessage(hUpDown, UDM_GETPOS32, 0, 0);
}
spinbox::spinbox(mainwindow* parent,int value):control(parent){
winId=CreateWindowEx(0, L"EDIT", std::to_wstring(value).c_str(), WS_CHILD | WS_VISIBLE | WS_BORDER|ES_NUMBER ,
0,0,0,0, parent->winId, NULL, NULL, NULL);
hUpDown = CreateWindowEx(0, UPDOWN_CLASS, NULL,
@ -39,6 +42,7 @@ spinbox::spinbox(mainwindow* parent,const std::wstring& text):control(parent){
0, 0, 0, 0,
parent->winId, NULL, NULL, NULL);
SendMessage(hUpDown, UDM_SETBUDDY, (WPARAM)winId, 0);
setminmax(0,0x7fffffff);
std::tie(minv,maxv)= getminmax();
}
void spinbox::setgeo(int x,int y,int w,int h)

View File

@ -47,10 +47,11 @@ class spinbox:public control{
int minv,maxv;
public:
void dispatch(WPARAM);
spinbox(mainwindow*,const std::wstring&);
spinbox(mainwindow*,int);
void setminmax(int,int);
std::pair<int,int>getminmax();
void setcurr(int);
int getcurr();
std::function<void(int)> onvaluechange=[&](int){};
void setgeo(int,int,int,int);
};

View File

@ -177,6 +177,6 @@ std::optional<std::wstring> commonparsestring(void* data,size_t length,void* php
auto hp=(HookParam*)php;
if (hp->type & CODEC_UTF16) return std::wstring((wchar_t*)data, length / sizeof(wchar_t));
else if(hp->type&CODEC_UTF32)return (std::move(utf32_to_utf16(data,length)));
else if (auto converted = StringToWideString(std::string((char*)data, length), hp->codepage ? hp->codepage : ((hp->type&CODEC_UTF8)?CP_UTF8:df))) return (converted.value());
else if (auto converted = StringToWideString(std::string((char*)data, length), (hp->type&CODEC_UTF8)?CP_UTF8:(hp->codepage ? hp->codepage :df))) return (converted.value());
else return {};
}