mirror of
https://github.com/Artikash/Textractor.git
synced 2024-12-24 01:14:12 +08:00
start implementing new GUI
This commit is contained in:
parent
ffeb4e2dad
commit
fe30b77a44
@ -35,6 +35,9 @@ FORMS += \
|
|||||||
win32: LIBS += \
|
win32: LIBS += \
|
||||||
-L$$PWD/../Builds/Debug/Debug/ -lvnrhost
|
-L$$PWD/../Builds/Debug/Debug/ -lvnrhost
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS_RELEASE += \
|
||||||
|
/MT
|
||||||
|
|
||||||
# Default rules for deployment.
|
# Default rules for deployment.
|
||||||
qnx: target.path = /tmp/$${TARGET}/bin
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
@ -1,17 +1,44 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "QMessageBox"
|
#include "QMessageBox"
|
||||||
#include "qlineedit.h"
|
#include "QLineEdit"
|
||||||
|
#include "QTableWidget"
|
||||||
|
#include "QInputDialog"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include <Psapi.h>
|
||||||
#include "../texthook/host.h"
|
#include "../texthook/host.h"
|
||||||
|
|
||||||
|
QTableWidget* processList;
|
||||||
|
|
||||||
|
QString GetModuleName(DWORD processId, HMODULE module = NULL)
|
||||||
|
{
|
||||||
|
HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||||
|
wchar_t buffer[MAX_PATH];
|
||||||
|
GetModuleFileNameExW(handle, module, buffer, MAX_PATH);
|
||||||
|
return QString::fromWCharArray(wcsrchr(buffer, L'\\') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnProcessAttach(DWORD processId)
|
||||||
|
{
|
||||||
|
processList->setItem(processList->rowCount(), 0, new QTableWidgetItem(QString::number(processId)));
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::MainWindow)
|
ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
|
Host::Start();
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->centralWidget->children().at(0), SIGNAL(returnPressed()), this, SLOT(onCommand()));
|
|
||||||
StartHost();
|
processList = this->findChild<QTableWidget*>("processList");
|
||||||
|
Host::RegisterProcessAttachCallback([](DWORD processId)
|
||||||
|
{
|
||||||
|
processList->insertRow(processList->rowCount());
|
||||||
|
processList->setItem(processList->rowCount() - 1, 0, new QTableWidgetItem(QString::number(processId)));
|
||||||
|
processList->setItem(processList->rowCount() - 1, 1, new QTableWidgetItem(GetModuleName(processId)));
|
||||||
|
});
|
||||||
|
Host::Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
@ -19,8 +46,9 @@ MainWindow::~MainWindow()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onCommand()
|
void MainWindow::on_attachButton_clicked()
|
||||||
{
|
{
|
||||||
QLineEdit* lineEdit = (QLineEdit*)sender();
|
//processList->insertRow(processList->rowCount());
|
||||||
QMessageBox::information(this, "called", lineEdit->text());
|
//processList->setItem(processList->rowCount() - 1, 0, new QTableWidgetItem(QString::number(6000)));
|
||||||
|
Host::InjectProcess(QInputDialog::getInt(this, "Process ID?", ""));
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui
|
||||||
class MainWindow;
|
{
|
||||||
|
class MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
@ -15,8 +16,10 @@ public:
|
|||||||
explicit MainWindow(QWidget *parent = nullptr);
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void onCommand();
|
|
||||||
|
void on_attachButton_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
};
|
};
|
||||||
|
@ -6,46 +6,110 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>496</width>
|
<width>800</width>
|
||||||
<height>376</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>NextHooker</string>
|
<string>NextHooker</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget">
|
<widget class="QWidget" name="centralWidget">
|
||||||
<widget class="QLineEdit" name="lineEdit">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="geometry">
|
<item>
|
||||||
<rect>
|
<widget class="QTextBrowser" name="textBrowser">
|
||||||
<x>252</x>
|
<property name="sizePolicy">
|
||||||
<y>0</y>
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<width>241</width>
|
<horstretch>5</horstretch>
|
||||||
<height>20</height>
|
<verstretch>0</verstretch>
|
||||||
</rect>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
</item>
|
||||||
<property name="geometry">
|
<item>
|
||||||
<rect>
|
<widget class="QFrame" name="processManager">
|
||||||
<x>3</x>
|
<property name="sizePolicy">
|
||||||
<y>40</y>
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<width>491</width>
|
<horstretch>2</horstretch>
|
||||||
<height>291</height>
|
<verstretch>0</verstretch>
|
||||||
</rect>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="attachButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Attach to game</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Currently attached to:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="processList">
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||||
|
<number>50</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>ID</string>
|
||||||
|
</property>
|
||||||
|
<property name="textAlignment">
|
||||||
|
<set>AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
<property name="textAlignment">
|
||||||
|
<set>AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenuBar" name="menuBar">
|
<widget class="QMenuBar" name="menuBar">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>496</width>
|
<width>800</width>
|
||||||
<height>21</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
project(host)
|
project(host)
|
||||||
|
|
||||||
set(vnrhost_src
|
set(vnrhost_src
|
||||||
hookman.h
|
|
||||||
host.h
|
host.h
|
||||||
pipe.h
|
pipe.h
|
||||||
textthread.h
|
textthread.h
|
||||||
winmutex.h
|
winmutex.h
|
||||||
hookman.cc
|
|
||||||
host.cc
|
host.cc
|
||||||
pipe.cc
|
pipe.cc
|
||||||
textthread.cc
|
textthread.cc
|
||||||
|
@ -1,155 +0,0 @@
|
|||||||
// hookman.cc
|
|
||||||
// 8/24/2013 jichi
|
|
||||||
// Branch IHF/HookManager.cpp, rev 133
|
|
||||||
// 8/24/2013 TODO: Clean up this file
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
|
||||||
# pragma warning (disable:4146) // C4146: unary minus operator applied to unsigned type
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#include "hookman.h"
|
|
||||||
#include "../vnrhook/include/const.h"
|
|
||||||
#include "../vnrhook/include/defs.h"
|
|
||||||
#include "../vnrhook/include/types.h"
|
|
||||||
#include "winmutex.h"
|
|
||||||
#include <atlbase.h>
|
|
||||||
|
|
||||||
#define HM_LOCK CriticalSectionLocker hmLocker(hmCs) // Synchronized scope for accessing private data
|
|
||||||
|
|
||||||
HookManager::HookManager() :
|
|
||||||
create(nullptr),
|
|
||||||
remove(nullptr),
|
|
||||||
attach(nullptr),
|
|
||||||
detach(nullptr),
|
|
||||||
nextThreadNumber(0),
|
|
||||||
splitDelay(250),
|
|
||||||
textThreadsByParams(),
|
|
||||||
processRecordsByIds()
|
|
||||||
{
|
|
||||||
InitializeCriticalSection(&hmCs);
|
|
||||||
// Console text thread
|
|
||||||
(textThreadsByParams[{ 0, -1UL, -1UL, -1UL }] = new TextThread({ 0, -1UL, -1UL, -1UL }, nextThreadNumber++, splitDelay))->Status() |= USING_UNICODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HookManager::~HookManager()
|
|
||||||
{
|
|
||||||
EnterCriticalSection(&hmCs);
|
|
||||||
RemoveThreads([](auto one, auto two) { return true; }, {});
|
|
||||||
for (auto i : processRecordsByIds) UnRegisterProcess(i.first);
|
|
||||||
LeaveCriticalSection(&hmCs);
|
|
||||||
DeleteCriticalSection(&hmCs);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextThread* HookManager::FindSingle(DWORD number)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
for (auto i : textThreadsByParams)
|
|
||||||
if (i.second->Number() == number)
|
|
||||||
return i.second;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HookManager::RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
std::vector<ThreadParameter> removedThreads;
|
|
||||||
for (auto i : textThreadsByParams)
|
|
||||||
if (RemoveIf(i.first, cmp))
|
|
||||||
{
|
|
||||||
if (remove) remove(i.second);
|
|
||||||
delete i.second;
|
|
||||||
removedThreads.push_back(i.first);
|
|
||||||
}
|
|
||||||
for (auto i : removedThreads) textThreadsByParams.erase(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HookManager::RegisterProcess(DWORD pid, HANDLE hostPipe)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
ProcessRecord record;
|
|
||||||
record.hostPipe = hostPipe;
|
|
||||||
record.hookman_section = OpenFileMappingW(FILE_MAP_READ, FALSE, (ITH_SECTION_ + std::to_wstring(pid)).c_str());
|
|
||||||
record.hookman_map = MapViewOfFile(record.hookman_section, FILE_MAP_READ, 0, 0, HOOK_SECTION_SIZE / 2); // jichi 1/16/2015: Changed to half to hook section size
|
|
||||||
record.process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
|
||||||
record.hookman_mutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(pid)).c_str());
|
|
||||||
processRecordsByIds[pid] = record;
|
|
||||||
if (attach) attach(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HookManager::UnRegisterProcess(DWORD pid)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
ProcessRecord pr = processRecordsByIds[pid];
|
|
||||||
CloseHandle(pr.hookman_mutex);
|
|
||||||
UnmapViewOfFile(pr.hookman_map);
|
|
||||||
CloseHandle(pr.process_handle);
|
|
||||||
CloseHandle(pr.hookman_section);
|
|
||||||
processRecordsByIds.erase(pid);
|
|
||||||
RemoveThreads([](auto one, auto two) { return one.pid == two.pid; }, { pid, 0, 0, 0 });
|
|
||||||
if (detach) detach(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HookManager::DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD spl, const BYTE *text, int len)
|
|
||||||
{
|
|
||||||
// jichi 20/27/2013: When PID is zero, the text comes from console, which I don't need
|
|
||||||
if (!text || !pid || len <= 0) return;
|
|
||||||
HM_LOCK;
|
|
||||||
ThreadParameter tp = { pid, hook, retn, spl };
|
|
||||||
TextThread *it;
|
|
||||||
if ((it = textThreadsByParams[tp]) == nullptr)
|
|
||||||
{
|
|
||||||
it = textThreadsByParams[tp] = new TextThread(tp, nextThreadNumber++, splitDelay);
|
|
||||||
if (GetHookParam(pid, hook).type & USING_UNICODE) it->Status() |= USING_UNICODE;
|
|
||||||
if (create) create(it);
|
|
||||||
}
|
|
||||||
it->AddText(text, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HookManager::AddConsoleOutput(std::wstring text)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
textThreadsByParams[{ 0, -1UL, -1UL, -1UL }]->AddSentence(std::wstring(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE HookManager::GetHostPipe(DWORD pid)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
return processRecordsByIds[pid].hostPipe;
|
|
||||||
}
|
|
||||||
|
|
||||||
HookParam HookManager::GetHookParam(DWORD pid, DWORD addr)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
HookParam ret = {};
|
|
||||||
ProcessRecord pr = processRecordsByIds[pid];
|
|
||||||
if (pr.hookman_map == nullptr) return ret;
|
|
||||||
MutexLocker locker(pr.hookman_mutex);
|
|
||||||
const Hook* hooks = (const Hook*)pr.hookman_map;
|
|
||||||
for (int i = 0; i < MAX_HOOK; ++i)
|
|
||||||
if (hooks[i].Address() == addr)
|
|
||||||
ret = hooks[i].hp;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring HookManager::GetHookName(DWORD pid, DWORD addr)
|
|
||||||
{
|
|
||||||
HM_LOCK;
|
|
||||||
std::string buffer = "";
|
|
||||||
ProcessRecord pr = processRecordsByIds[pid];
|
|
||||||
if (pr.hookman_map == nullptr) return L"";
|
|
||||||
MutexLocker locker(pr.hookman_mutex);
|
|
||||||
const Hook* hooks = (const Hook*)pr.hookman_map;
|
|
||||||
for (int i = 0; i < MAX_HOOK; ++i)
|
|
||||||
{
|
|
||||||
if (hooks[i].Address() == addr)
|
|
||||||
{
|
|
||||||
buffer.resize(hooks[i].NameLength());
|
|
||||||
ReadProcessMemory(pr.process_handle, hooks[i].Name(), &buffer[0], hooks[i].NameLength(), nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
USES_CONVERSION;
|
|
||||||
return std::wstring(A2W(buffer.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF
|
|
@ -1,70 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// hookman.h
|
|
||||||
// 8/23/2013 jichi
|
|
||||||
// Branch: ITH/HookManager.h, rev 133
|
|
||||||
|
|
||||||
#include <Windows.h>
|
|
||||||
#include "textthread.h"
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
|
||||||
#include "../vnrhook/include/types.h"
|
|
||||||
|
|
||||||
struct ProcessRecord
|
|
||||||
{
|
|
||||||
HANDLE process_handle;
|
|
||||||
HANDLE hookman_mutex;
|
|
||||||
HANDLE hookman_section;
|
|
||||||
LPVOID hookman_map;
|
|
||||||
HANDLE hostPipe;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void(*ProcessEventCallback)(DWORD pid);
|
|
||||||
typedef void(*ThreadEventCallback)(TextThread*);
|
|
||||||
|
|
||||||
struct ThreadParameterHasher
|
|
||||||
{
|
|
||||||
size_t operator()(const ThreadParameter& tp) const
|
|
||||||
{
|
|
||||||
return std::hash<DWORD>()(tp.pid << 6) + std::hash<DWORD>()(tp.hook) + std::hash<DWORD>()(tp.retn) + std::hash<DWORD>()(tp.spl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Artikash 7/19/2018: This should probably be broken up into 2-4 classes...
|
|
||||||
class __declspec(dllexport) HookManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HookManager();
|
|
||||||
~HookManager();
|
|
||||||
|
|
||||||
TextThread* FindSingle(DWORD number);
|
|
||||||
void AddConsoleOutput(std::wstring text);
|
|
||||||
void DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD split, const BYTE *text, int len);
|
|
||||||
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp);
|
|
||||||
void RegisterProcess(DWORD pid, HANDLE hostPipe);
|
|
||||||
void UnRegisterProcess(DWORD pid);
|
|
||||||
HANDLE GetHostPipe(DWORD pid);
|
|
||||||
HookParam GetHookParam(DWORD pid, DWORD addr);
|
|
||||||
std::wstring GetHookName(DWORD pid, DWORD addr);
|
|
||||||
|
|
||||||
void RegisterThreadCreateCallback(ThreadEventCallback cf) { create = cf; }
|
|
||||||
void RegisterThreadRemoveCallback(ThreadEventCallback cf) { remove = cf; }
|
|
||||||
void RegisterProcessAttachCallback(ProcessEventCallback cf) { attach = cf; }
|
|
||||||
void RegisterProcessDetachCallback(ProcessEventCallback cf) { detach = cf; }
|
|
||||||
|
|
||||||
void SetSplitInterval(unsigned int splitDelay) { this->splitDelay = splitDelay; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unordered_map<ThreadParameter, TextThread*, ThreadParameterHasher> textThreadsByParams;
|
|
||||||
std::unordered_map<DWORD, ProcessRecord> processRecordsByIds;
|
|
||||||
|
|
||||||
CRITICAL_SECTION hmCs;
|
|
||||||
|
|
||||||
ThreadEventCallback create, remove;
|
|
||||||
ProcessEventCallback attach, detach;
|
|
||||||
|
|
||||||
WORD nextThreadNumber;
|
|
||||||
unsigned int splitDelay;
|
|
||||||
};
|
|
||||||
|
|
||||||
// EOF
|
|
308
texthook/host.cc
308
texthook/host.cc
@ -4,28 +4,37 @@
|
|||||||
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
|
#include "winmutex.h"
|
||||||
|
#include <atlbase.h>
|
||||||
#include "../vnrhook/include/const.h"
|
#include "../vnrhook/include/const.h"
|
||||||
#include "../vnrhook/include/defs.h"
|
#include "../vnrhook/include/defs.h"
|
||||||
#include "../vnrhook/include/types.h"
|
#include "../vnrhook/include/types.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
HANDLE preventDuplicationMutex;
|
HANDLE preventDuplicationMutex;
|
||||||
|
|
||||||
HookManager* man;
|
std::unordered_map<ThreadParameter, TextThread*, ThreadParameterHasher> textThreadsByParams;
|
||||||
|
std::unordered_map<DWORD, ProcessRecord> processRecordsByIds;
|
||||||
|
|
||||||
|
CRITICAL_SECTION hostCs;
|
||||||
|
|
||||||
|
ThreadEventCallback onCreate, onRemove;
|
||||||
|
ProcessEventCallback onAttach, onDetach;
|
||||||
|
|
||||||
|
WORD nextThreadNumber;
|
||||||
HWND dummyWindow;
|
HWND dummyWindow;
|
||||||
bool running;
|
bool running;
|
||||||
|
|
||||||
namespace
|
#define HOST_LOCK CriticalSectionLocker hostLocker(hostCs) // Synchronized scope for accessing private data
|
||||||
{ // unnamed
|
|
||||||
void GetDebugPrivileges() // Artikash 5/19/2018: Is it just me or is this function 100% superfluous?
|
|
||||||
{
|
|
||||||
HANDLE processToken;
|
|
||||||
TOKEN_PRIVILEGES Privileges = { 1, {0x14, 0, SE_PRIVILEGE_ENABLED} };
|
|
||||||
|
|
||||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &processToken);
|
void GetDebugPrivileges() // Artikash 5/19/2018: Is it just me or is this function 100% superfluous?
|
||||||
AdjustTokenPrivileges(processToken, FALSE, &Privileges, 0, nullptr, nullptr);
|
{
|
||||||
CloseHandle(processToken);
|
HANDLE processToken;
|
||||||
}
|
TOKEN_PRIVILEGES Privileges = { 1, {0x14, 0, SE_PRIVILEGE_ENABLED} };
|
||||||
} // unnamed namespace
|
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &processToken);
|
||||||
|
AdjustTokenPrivileges(processToken, FALSE, &Privileges, 0, nullptr, nullptr);
|
||||||
|
CloseHandle(processToken);
|
||||||
|
}
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused)
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused)
|
||||||
{
|
{
|
||||||
@ -33,12 +42,11 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused)
|
|||||||
{
|
{
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
DisableThreadLibraryCalls(hinstDLL);
|
||||||
GetDebugPrivileges();
|
|
||||||
// jichi 8/24/2013: Create hidden window so that ITH can access timer and events
|
// jichi 8/24/2013: Create hidden window so that ITH can access timer and events
|
||||||
dummyWindow = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
|
dummyWindow = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
CloseHost();
|
Host::Close();
|
||||||
DestroyWindow(dummyWindow);
|
DestroyWindow(dummyWindow);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -47,112 +55,222 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID unused)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLEXPORT bool StartHost()
|
namespace Host
|
||||||
{
|
{
|
||||||
preventDuplicationMutex = CreateMutexW(nullptr, TRUE, ITH_SERVER_MUTEX);
|
DLLEXPORT bool Start()
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS || ::running)
|
|
||||||
{
|
{
|
||||||
MessageBoxW(nullptr, L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!", L"Error", MB_ICONERROR);
|
preventDuplicationMutex = CreateMutexW(nullptr, TRUE, ITH_SERVER_MUTEX);
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS || running)
|
||||||
|
{
|
||||||
|
MessageBoxW(nullptr, L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!", L"Error", MB_ICONERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
running = true;
|
||||||
|
GetDebugPrivileges();
|
||||||
|
InitializeCriticalSection(&hostCs);
|
||||||
|
onAttach = onDetach = nullptr;
|
||||||
|
onCreate = onRemove = nullptr;
|
||||||
|
nextThreadNumber = 0;
|
||||||
|
// Console text thread
|
||||||
|
(textThreadsByParams[{ 0, -1UL, -1UL, -1UL }] = new TextThread({ 0, -1UL, -1UL, -1UL }, nextThreadNumber++))->Status() |= USING_UNICODE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void Open()
|
||||||
|
{
|
||||||
|
CreateNewPipe();
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void Close()
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&hostCs);
|
||||||
|
running = false;
|
||||||
|
RemoveThreads([](auto one, auto two) { return true; }, {});
|
||||||
|
for (auto i : processRecordsByIds) UnregisterProcess(i.first);
|
||||||
|
LeaveCriticalSection(&hostCs);
|
||||||
|
DeleteCriticalSection(&hostCs);
|
||||||
|
CloseHandle(preventDuplicationMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT bool InjectProcess(DWORD processId, DWORD timeout)
|
||||||
|
{
|
||||||
|
if (processId == GetCurrentProcessId()) return false;
|
||||||
|
|
||||||
|
CloseHandle(CreateMutexW(nullptr, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)).c_str()));
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
AddConsoleOutput(L"already locked");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE textHooker = LoadLibraryExW(ITH_DLL, nullptr, DONT_RESOLVE_DLL_REFERENCES);
|
||||||
|
wchar_t textHookerPath[MAX_PATH];
|
||||||
|
unsigned int textHookerPathSize = GetModuleFileNameW(textHooker, textHookerPath, MAX_PATH) * 2 + 2;
|
||||||
|
FreeLibrary(textHooker);
|
||||||
|
|
||||||
|
if (HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId))
|
||||||
|
if (LPVOID remoteData = VirtualAllocEx(processHandle, nullptr, textHookerPathSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
|
||||||
|
if (WriteProcessMemory(processHandle, remoteData, textHookerPath, textHookerPathSize, nullptr))
|
||||||
|
if (HANDLE thread = CreateRemoteThread(processHandle, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
|
||||||
|
{
|
||||||
|
WaitForSingleObject(thread, timeout);
|
||||||
|
CloseHandle(thread);
|
||||||
|
VirtualFreeEx(processHandle, remoteData, 0, MEM_RELEASE);
|
||||||
|
CloseHandle(processHandle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddConsoleOutput(L"couldn't inject dll");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
DLLEXPORT bool DetachProcess(DWORD processId)
|
||||||
{
|
{
|
||||||
::running = true;
|
DWORD command = HOST_COMMAND_DETACH;
|
||||||
::man = new HookManager;
|
DWORD unused;
|
||||||
|
return WriteFile(processRecordsByIds[processId].hostPipe, &command, sizeof(command), &unused, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name)
|
||||||
|
{
|
||||||
|
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||||
|
*(DWORD*)buffer = HOST_COMMAND_NEW_HOOK;
|
||||||
|
*(HookParam*)(buffer + sizeof(DWORD)) = hp;
|
||||||
|
if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str());
|
||||||
|
DWORD unused;
|
||||||
|
return WriteFile(processRecordsByIds[pid].hostPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), &unused, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr)
|
||||||
|
{
|
||||||
|
HANDLE hostPipe = processRecordsByIds[pid].hostPipe;
|
||||||
|
if (hostPipe == nullptr) return false;
|
||||||
|
HANDLE hookRemovalEvent = CreateEventW(nullptr, TRUE, FALSE, ITH_REMOVEHOOK_EVENT);
|
||||||
|
BYTE buffer[sizeof(DWORD) * 2] = {};
|
||||||
|
*(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK;
|
||||||
|
*(DWORD*)(buffer + sizeof(DWORD)) = addr;
|
||||||
|
DWORD unused;
|
||||||
|
WriteFile(hostPipe, buffer, sizeof(DWORD) * 2, &unused, nullptr);
|
||||||
|
WaitForSingleObject(hookRemovalEvent, 1000);
|
||||||
|
CloseHandle(hookRemovalEvent);
|
||||||
|
RemoveThreads([](auto one, auto two) { return one.pid == two.pid && one.hook == two.hook; }, { pid, addr, 0, 0 });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DLLEXPORT void OpenHost()
|
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr)
|
||||||
{
|
|
||||||
CreateNewPipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
DLLEXPORT void CloseHost()
|
|
||||||
{
|
|
||||||
if (::running)
|
|
||||||
{
|
{
|
||||||
::running = false;
|
HOST_LOCK;
|
||||||
delete man;
|
HookParam ret = {};
|
||||||
CloseHandle(preventDuplicationMutex);
|
ProcessRecord pr = processRecordsByIds[pid];
|
||||||
}
|
if (pr.hookman_map == nullptr) return ret;
|
||||||
}
|
MutexLocker locker(pr.hookman_mutex);
|
||||||
|
const Hook* hooks = (const Hook*)pr.hookman_map;
|
||||||
DLLEXPORT bool InjectProcess(DWORD processId, DWORD timeout)
|
for (int i = 0; i < MAX_HOOK; ++i)
|
||||||
{
|
if (hooks[i].Address() == addr)
|
||||||
if (processId == GetCurrentProcessId()) return false;
|
ret = hooks[i].hp;
|
||||||
|
return ret;
|
||||||
CloseHandle(CreateMutexW(nullptr, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)).c_str()));
|
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
|
||||||
man->AddConsoleOutput(L"already locked");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HMODULE textHooker = LoadLibraryExW(ITH_DLL, nullptr, DONT_RESOLVE_DLL_REFERENCES);
|
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr)
|
||||||
wchar_t textHookerPath[MAX_PATH];
|
{
|
||||||
unsigned int textHookerPathSize = GetModuleFileNameW(textHooker, textHookerPath, MAX_PATH) * 2 + 2;
|
HOST_LOCK;
|
||||||
FreeLibrary(textHooker);
|
std::string buffer = "";
|
||||||
|
ProcessRecord pr = processRecordsByIds[pid];
|
||||||
|
if (pr.hookman_map == nullptr) return L"";
|
||||||
|
MutexLocker locker(pr.hookman_mutex);
|
||||||
|
const Hook* hooks = (const Hook*)pr.hookman_map;
|
||||||
|
for (int i = 0; i < MAX_HOOK; ++i)
|
||||||
|
if (hooks[i].Address() == addr)
|
||||||
|
{
|
||||||
|
buffer.resize(hooks[i].NameLength());
|
||||||
|
ReadProcessMemory(pr.process_handle, hooks[i].Name(), &buffer[0], hooks[i].NameLength(), nullptr);
|
||||||
|
}
|
||||||
|
USES_CONVERSION;
|
||||||
|
return std::wstring(A2W(buffer.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
if (HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId))
|
DLLEXPORT TextThread* GetThread(DWORD number)
|
||||||
if (LPVOID remoteData = VirtualAllocEx(processHandle, nullptr, textHookerPathSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
|
{
|
||||||
if (WriteProcessMemory(processHandle, remoteData, textHookerPath, textHookerPathSize, nullptr))
|
HOST_LOCK;
|
||||||
if (HANDLE thread = CreateRemoteThread(processHandle, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
|
for (auto i : textThreadsByParams)
|
||||||
{
|
if (i.second->Number() == number)
|
||||||
WaitForSingleObject(thread, timeout);
|
return i.second;
|
||||||
CloseHandle(thread);
|
return nullptr;
|
||||||
VirtualFreeEx(processHandle, remoteData, 0, MEM_RELEASE);
|
}
|
||||||
CloseHandle(processHandle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
man->AddConsoleOutput(L"couldn't inject dll");
|
DLLEXPORT void AddConsoleOutput(std::wstring text)
|
||||||
return false;
|
{
|
||||||
|
HOST_LOCK;
|
||||||
|
textThreadsByParams[{ 0, -1UL, -1UL, -1UL }]->AddSentence(std::wstring(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf) { onCreate = cf; }
|
||||||
|
DLLEXPORT void RegisterThreadRemoveCallback(ThreadEventCallback cf) { onRemove = cf; }
|
||||||
|
DLLEXPORT void RegisterProcessAttachCallback(ProcessEventCallback cf) { onAttach = cf; }
|
||||||
|
DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf) { onDetach = cf; }
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLEXPORT bool DetachProcess(DWORD processId)
|
void DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD split, const BYTE * text, int len)
|
||||||
{
|
{
|
||||||
DWORD command = HOST_COMMAND_DETACH;
|
// jichi 20/27/2013: When PID is zero, the text comes from console, which I don't need
|
||||||
DWORD unused;
|
if (!text || !pid || len <= 0) return;
|
||||||
return WriteFile(man->GetHostPipe(processId), &command, sizeof(command), &unused, nullptr);
|
HOST_LOCK;
|
||||||
|
ThreadParameter tp = { pid, hook, retn, split };
|
||||||
|
TextThread *it;
|
||||||
|
if ((it = textThreadsByParams[tp]) == nullptr)
|
||||||
|
{
|
||||||
|
it = textThreadsByParams[tp] = new TextThread(tp, nextThreadNumber++);
|
||||||
|
if (Host::GetHookParam(pid, hook).type & USING_UNICODE) it->Status() |= USING_UNICODE;
|
||||||
|
if (onCreate) onCreate(it);
|
||||||
|
}
|
||||||
|
it->AddText(text, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLEXPORT HookManager* GetHostHookManager()
|
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp)
|
||||||
{
|
{
|
||||||
return man;
|
HOST_LOCK;
|
||||||
|
std::vector<ThreadParameter> removedThreads;
|
||||||
|
for (auto i : textThreadsByParams)
|
||||||
|
if (RemoveIf(i.first, cmp))
|
||||||
|
{
|
||||||
|
if (onRemove) onRemove(i.second);
|
||||||
|
delete i.second;
|
||||||
|
removedThreads.push_back(i.first);
|
||||||
|
}
|
||||||
|
for (auto i : removedThreads) textThreadsByParams.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name)
|
void RegisterProcess(DWORD pid, HANDLE hostPipe)
|
||||||
{
|
{
|
||||||
HANDLE commandPipe = man->GetHostPipe(pid);
|
HOST_LOCK;
|
||||||
if (commandPipe == nullptr) return false;
|
ProcessRecord record;
|
||||||
|
record.hostPipe = hostPipe;
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
record.hookman_section = OpenFileMappingW(FILE_MAP_READ, FALSE, (ITH_SECTION_ + std::to_wstring(pid)).c_str());
|
||||||
*(DWORD*)buffer = HOST_COMMAND_NEW_HOOK;
|
record.hookman_map = MapViewOfFile(record.hookman_section, FILE_MAP_READ, 0, 0, HOOK_SECTION_SIZE / 2); // jichi 1/16/2015: Changed to half to hook section size
|
||||||
*(HookParam*)(buffer + sizeof(DWORD)) = hp;
|
record.process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||||
if (name.size()) strcpy((char*)buffer + sizeof(DWORD) + sizeof(HookParam), name.c_str());
|
record.hookman_mutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, (ITH_HOOKMAN_MUTEX_ + std::to_wstring(pid)).c_str());
|
||||||
DWORD unused;
|
processRecordsByIds[pid] = record;
|
||||||
return WriteFile(commandPipe, buffer, sizeof(DWORD) + sizeof(HookParam) + name.size(), &unused, nullptr);
|
if (onAttach) onAttach(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr)
|
void UnregisterProcess(DWORD pid)
|
||||||
{
|
{
|
||||||
HANDLE commandPipe = man->GetHostPipe(pid);
|
HOST_LOCK;
|
||||||
if (commandPipe == nullptr) return false;
|
ProcessRecord pr = processRecordsByIds[pid];
|
||||||
|
if (!pr.hostPipe) return;
|
||||||
HANDLE hookRemovalEvent = CreateEventW(nullptr, TRUE, FALSE, ITH_REMOVEHOOK_EVENT);
|
CloseHandle(pr.hookman_mutex);
|
||||||
|
UnmapViewOfFile(pr.hookman_map);
|
||||||
BYTE buffer[sizeof(DWORD) * 2] = {};
|
CloseHandle(pr.process_handle);
|
||||||
*(DWORD*)buffer = HOST_COMMAND_REMOVE_HOOK;
|
CloseHandle(pr.hookman_section);
|
||||||
*(DWORD*)(buffer + sizeof(DWORD)) = addr;
|
processRecordsByIds.erase(pid);
|
||||||
DWORD unused;
|
RemoveThreads([](auto one, auto two) { return one.pid == two.pid; }, { pid, 0, 0, 0 });
|
||||||
WriteFile(commandPipe, buffer, sizeof(DWORD) * 2, &unused, nullptr);
|
if (onDetach) onDetach(pid);
|
||||||
|
|
||||||
WaitForSingleObject(hookRemovalEvent, 1000);
|
|
||||||
CloseHandle(hookRemovalEvent);
|
|
||||||
|
|
||||||
man->RemoveThreads([](auto one, auto two) { return one.pid == two.pid && one.hook == two.hook; }, { pid, addr, 0, 0 });
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
@ -5,17 +5,57 @@
|
|||||||
// Branch: ITH/IHF.h, rev 105
|
// Branch: ITH/IHF.h, rev 105
|
||||||
|
|
||||||
#define DLLEXPORT __declspec(dllexport)
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
#include "hookman.h"
|
|
||||||
#include "../vnrhook/include/types.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
DLLEXPORT void OpenHost();
|
#include <Windows.h>
|
||||||
DLLEXPORT bool StartHost();
|
#include "textthread.h"
|
||||||
DLLEXPORT void CloseHost();
|
#include <string>
|
||||||
DLLEXPORT HookManager* GetHostHookManager();
|
#include "../vnrhook/include/types.h"
|
||||||
DLLEXPORT bool InjectProcess(DWORD pid, DWORD timeout = 5000);
|
|
||||||
DLLEXPORT bool DetachProcess(DWORD pid);
|
struct ProcessRecord
|
||||||
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = "");
|
{
|
||||||
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr);
|
HANDLE process_handle;
|
||||||
|
HANDLE hookman_mutex;
|
||||||
|
HANDLE hookman_section;
|
||||||
|
LPVOID hookman_map;
|
||||||
|
HANDLE hostPipe;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void(*ProcessEventCallback)(DWORD pid);
|
||||||
|
typedef void(*ThreadEventCallback)(TextThread*);
|
||||||
|
|
||||||
|
struct ThreadParameterHasher
|
||||||
|
{
|
||||||
|
size_t operator()(const ThreadParameter& tp) const
|
||||||
|
{
|
||||||
|
return std::hash<DWORD>()(tp.pid << 6) + std::hash<DWORD>()(tp.hook) + std::hash<DWORD>()(tp.retn) + std::hash<DWORD>()(tp.spl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Host
|
||||||
|
{
|
||||||
|
DLLEXPORT void Open();
|
||||||
|
DLLEXPORT bool Start();
|
||||||
|
DLLEXPORT void Close();
|
||||||
|
DLLEXPORT bool InjectProcess(DWORD pid, DWORD timeout = 5000);
|
||||||
|
DLLEXPORT bool DetachProcess(DWORD pid);
|
||||||
|
|
||||||
|
DLLEXPORT bool InsertHook(DWORD pid, HookParam hp, std::string name = "");
|
||||||
|
DLLEXPORT bool RemoveHook(DWORD pid, DWORD addr);
|
||||||
|
DLLEXPORT HookParam GetHookParam(DWORD pid, DWORD addr);
|
||||||
|
DLLEXPORT std::wstring GetHookName(DWORD pid, DWORD addr);
|
||||||
|
|
||||||
|
DLLEXPORT TextThread* GetThread(DWORD number);
|
||||||
|
DLLEXPORT void AddConsoleOutput(std::wstring text);
|
||||||
|
|
||||||
|
DLLEXPORT void RegisterThreadCreateCallback(ThreadEventCallback cf);
|
||||||
|
DLLEXPORT void RegisterThreadRemoveCallback(ThreadEventCallback cf);
|
||||||
|
DLLEXPORT void RegisterProcessAttachCallback(ProcessEventCallback cf);
|
||||||
|
DLLEXPORT void RegisterProcessDetachCallback(ProcessEventCallback cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchText(DWORD pid, DWORD hook, DWORD retn, DWORD split, const BYTE *text, int len);
|
||||||
|
void RemoveThreads(bool(*RemoveIf)(ThreadParameter, ThreadParameter), ThreadParameter cmp);
|
||||||
|
void RegisterProcess(DWORD pid, HANDLE hostPipe);
|
||||||
|
void UnregisterProcess(DWORD pid);
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
#include "../vnrhook/include/const.h"
|
#include "../vnrhook/include/const.h"
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
|
|
||||||
extern HookManager* man;
|
|
||||||
|
|
||||||
struct Pipes
|
struct Pipes
|
||||||
{
|
{
|
||||||
HANDLE hookPipe;
|
HANDLE hookPipe;
|
||||||
@ -34,7 +32,7 @@ DWORD WINAPI TextReceiver(LPVOID lpThreadParameter)
|
|||||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||||
DWORD bytesRead, processId;
|
DWORD bytesRead, processId;
|
||||||
ReadFile(pipes->hookPipe, &processId, sizeof(processId), &bytesRead, nullptr);
|
ReadFile(pipes->hookPipe, &processId, sizeof(processId), &bytesRead, nullptr);
|
||||||
man->RegisterProcess(processId, pipes->hostPipe);
|
RegisterProcess(processId, pipes->hostPipe);
|
||||||
|
|
||||||
// jichi 9/27/2013: why recursion?
|
// jichi 9/27/2013: why recursion?
|
||||||
// Artikash 5/20/2018: To create a new pipe for another process
|
// Artikash 5/20/2018: To create a new pipe for another process
|
||||||
@ -55,13 +53,13 @@ DWORD WINAPI TextReceiver(LPVOID lpThreadParameter)
|
|||||||
case HOST_NOTIFICATION_NEWHOOK: // Artikash 7/18/2018: Useless for now, but could be used to implement smth later
|
case HOST_NOTIFICATION_NEWHOOK: // Artikash 7/18/2018: Useless for now, but could be used to implement smth later
|
||||||
break;
|
break;
|
||||||
case HOST_NOTIFICATION_TEXT:
|
case HOST_NOTIFICATION_TEXT:
|
||||||
man->AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text
|
Host::AddConsoleOutput(A2W((LPCSTR)(buffer + sizeof(DWORD) * 2))); // Text
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
man->DispatchText(processId,
|
DispatchText(processId,
|
||||||
*(DWORD*)buffer, // Hook address
|
*(DWORD*)buffer, // Hook address
|
||||||
*(DWORD*)(buffer + sizeof(DWORD)), // Return address
|
*(DWORD*)(buffer + sizeof(DWORD)), // Return address
|
||||||
*(DWORD*)(buffer + sizeof(DWORD) * 2), // Split
|
*(DWORD*)(buffer + sizeof(DWORD) * 2), // Split
|
||||||
@ -73,7 +71,7 @@ DWORD WINAPI TextReceiver(LPVOID lpThreadParameter)
|
|||||||
|
|
||||||
DisconnectNamedPipe(pipes->hookPipe);
|
DisconnectNamedPipe(pipes->hookPipe);
|
||||||
DisconnectNamedPipe(pipes->hostPipe);
|
DisconnectNamedPipe(pipes->hostPipe);
|
||||||
man->UnRegisterProcess(processId);
|
UnregisterProcess(processId);
|
||||||
CloseHandle(pipes->hookPipe);
|
CloseHandle(pipes->hookPipe);
|
||||||
CloseHandle(pipes->hostPipe);
|
CloseHandle(pipes->hostPipe);
|
||||||
delete pipes;
|
delete pipes;
|
||||||
|
@ -5,12 +5,10 @@
|
|||||||
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#include "host.h"
|
|
||||||
#include "textthread.h"
|
#include "textthread.h"
|
||||||
#include "../vnrhook/include/const.h"
|
#include "../vnrhook/include/const.h"
|
||||||
#include "winmutex.h"
|
#include "winmutex.h"
|
||||||
|
|
||||||
extern HookManager* man;
|
|
||||||
extern HWND dummyWindow;
|
extern HWND dummyWindow;
|
||||||
|
|
||||||
#define TT_LOCK CriticalSectionLocker ttLocker(ttCs) // Synchronized scope for accessing private data
|
#define TT_LOCK CriticalSectionLocker ttLocker(ttCs) // Synchronized scope for accessing private data
|
||||||
|
@ -30,7 +30,7 @@ typedef std::wstring(*ThreadOutputCallback)(TextThread*, std::wstring data);
|
|||||||
class TextThread
|
class TextThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextThread(ThreadParameter tp, unsigned int threadNumber, unsigned int splitDelay);
|
TextThread(ThreadParameter tp, unsigned int threadNumber, unsigned int splitDelay = 250);
|
||||||
~TextThread();
|
~TextThread();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
@ -42,6 +42,7 @@ public:
|
|||||||
DWORD &Status() { return status; }
|
DWORD &Status() { return status; }
|
||||||
WORD Number() const { return threadNumber; }
|
WORD Number() const { return threadNumber; }
|
||||||
ThreadParameter GetThreadParameter() { return tp; }
|
ThreadParameter GetThreadParameter() { return tp; }
|
||||||
|
void SetSplitDelay(unsigned int splitDelay) { this->splitDelay = splitDelay; }
|
||||||
|
|
||||||
void RegisterOutputCallBack(ThreadOutputCallback cb) { output = cb; }
|
void RegisterOutputCallBack(ThreadOutputCallback cb) { output = cb; }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user