2018-07-22 06:40:16 +08:00
# include "mainwindow.h"
# include "ui_mainwindow.h"
2018-07-27 13:42:21 +08:00
# include "extensions.h"
2018-07-26 12:48:18 +08:00
# include "misc.h"
2018-08-23 03:11:40 +08:00
# include <QCoreApplication>
# include <QInputDialog>
# include <QFileDialog>
2018-07-24 03:25:02 +08:00
2018-07-22 06:40:16 +08:00
MainWindow : : MainWindow ( QWidget * parent ) :
2018-07-26 01:46:59 +08:00
QMainWindow ( parent ) ,
2018-08-22 10:43:30 +08:00
ui ( new Ui : : MainWindow )
2018-07-22 06:40:16 +08:00
{
2018-07-26 01:46:59 +08:00
ui - > setupUi ( this ) ;
2018-08-22 10:43:30 +08:00
2018-08-20 23:00:34 +08:00
QFile settings ( " NHWindow " ) ;
settings . open ( QIODevice : : ReadOnly ) ;
QDataStream reader ( & settings ) ;
QRect rect = QRect ( ) ;
reader > > rect ;
if ( rect . bottom ( ) ) this - > setGeometry ( rect ) ;
2018-07-24 03:25:02 +08:00
2018-08-22 10:43:30 +08:00
processCombo = findChild < QComboBox * > ( " processCombo " ) ;
ttCombo = findChild < QComboBox * > ( " ttCombo " ) ;
extenCombo = findChild < QComboBox * > ( " extenCombo " ) ;
textOutput = findChild < QPlainTextEdit * > ( " textOutput " ) ;
connect ( this , & MainWindow : : SigAddProcess , this , & MainWindow : : AddProcess ) ;
connect ( this , & MainWindow : : SigRemoveProcess , this , & MainWindow : : RemoveProcess ) ;
connect ( this , & MainWindow : : SigAddThread , this , & MainWindow : : AddThread ) ;
connect ( this , & MainWindow : : SigRemoveThread , this , & MainWindow : : RemoveThread ) ;
connect ( this , & MainWindow : : SigThreadOutput , this , & MainWindow : : ThreadOutput ) ;
Host : : Start (
[ & ] ( DWORD processId ) { emit SigAddProcess ( processId ) ; } ,
[ & ] ( DWORD processId ) { emit SigRemoveProcess ( processId ) ; } ,
[ & ] ( TextThread * thread ) { emit SigAddThread ( thread ) ; } ,
[ & ] ( TextThread * thread ) { emit SigRemoveThread ( thread ) ; }
) ;
2018-08-18 02:37:37 +08:00
ReloadExtensions ( ) ;
2018-08-31 04:09:20 +08:00
Host : : AddConsoleOutput ( L " NextHooker beta v3.0.0 by Artikash \r \n Source code and more information available under GPLv3 at https://github.com/Artikash/NextHooker " ) ;
2018-07-22 06:40:16 +08:00
}
MainWindow : : ~ MainWindow ( )
{
2018-08-20 23:00:34 +08:00
QFile settings ( " NHWindow " ) ;
settings . open ( QIODevice : : ReadWrite | QIODevice : : Truncate ) ;
QDataStream writer ( & settings ) ;
writer < < this - > geometry ( ) ;
2018-08-22 13:22:34 +08:00
Host : : Close ( ) ;
2018-07-26 01:46:59 +08:00
delete ui ;
2018-07-22 06:40:16 +08:00
}
2018-07-23 07:53:51 +08:00
2018-07-25 01:39:02 +08:00
void MainWindow : : AddProcess ( unsigned int processId )
2018-07-24 13:57:54 +08:00
{
2018-08-23 03:11:40 +08:00
processCombo - > addItem ( QString : : number ( processId ) + " : " + GetModuleName ( processId ) ) ;
2018-07-27 13:42:21 +08:00
QFile file ( " SavedHooks.txt " ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) return ;
QString processName = GetFullModuleName ( processId ) ;
QString allData = file . readAll ( ) ;
QStringList allProcesses = allData . split ( " \r " , QString : : SkipEmptyParts ) ;
2018-08-26 05:08:45 +08:00
for ( int i = allProcesses . size ( ) - 1 ; i > = 0 ; - - i )
if ( allProcesses [ i ] . contains ( processName ) )
2018-07-27 13:42:21 +08:00
{
2018-08-26 05:08:45 +08:00
QStringList hooks = allProcesses [ i ] . split ( " , " ) ;
for ( int j = 1 ; j < hooks . size ( ) ; + + j )
Host : : InsertHook ( processId , ParseCode ( hooks [ j ] ) . value_or ( HookParam ( ) ) ) ;
2018-07-27 13:42:21 +08:00
return ;
}
2018-07-24 13:57:54 +08:00
}
2018-07-25 01:39:02 +08:00
void MainWindow : : RemoveProcess ( unsigned int processId )
2018-07-24 13:57:54 +08:00
{
2018-07-26 01:46:59 +08:00
processCombo - > removeItem ( processCombo - > findText ( QString : : number ( processId ) + " : " , Qt : : MatchStartsWith ) ) ;
2018-07-24 13:57:54 +08:00
}
2018-07-25 01:39:02 +08:00
void MainWindow : : AddThread ( TextThread * thread )
2018-07-24 13:57:54 +08:00
{
2018-07-26 01:46:59 +08:00
ttCombo - > addItem (
TextThreadString ( thread ) +
2018-08-23 23:53:23 +08:00
QString : : fromStdWString ( Host : : GetHookName ( thread - > GetThreadParam ( ) . pid , thread - > GetThreadParam ( ) . hook ) ) +
2018-07-26 12:48:18 +08:00
" ( " +
2018-08-23 23:53:23 +08:00
GenerateCode ( Host : : GetHookParam ( thread - > GetThreadParam ( ) ) , thread - > GetThreadParam ( ) . pid ) +
2018-07-26 12:48:18 +08:00
" ) "
2018-07-26 01:46:59 +08:00
) ;
2018-08-03 12:07:25 +08:00
thread - > RegisterOutputCallBack ( [ & ] ( TextThread * thread , std : : wstring output )
{
2018-09-01 16:23:29 +08:00
if ( DispatchSentenceToExtensions ( output , GetInfoForExtensions ( thread ) ) )
{
output + = L " \r \n " ;
emit SigThreadOutput ( thread , QString : : fromStdWString ( output ) ) ;
}
2018-08-03 12:07:25 +08:00
return output ;
} ) ;
2018-07-24 13:57:54 +08:00
}
2018-07-25 01:39:02 +08:00
void MainWindow : : RemoveThread ( TextThread * thread )
2018-07-24 13:57:54 +08:00
{
2018-08-22 10:43:30 +08:00
int threadIndex = ttCombo - > findText ( TextThreadString ( thread ) , Qt : : MatchStartsWith ) ;
2018-07-26 01:46:59 +08:00
if ( threadIndex = = ttCombo - > currentIndex ( ) )
{
ttCombo - > setCurrentIndex ( 0 ) ;
on_ttCombo_activated ( 0 ) ;
}
2018-08-02 14:17:20 +08:00
ttCombo - > removeItem ( threadIndex ) ;
2018-08-22 10:43:30 +08:00
delete thread ;
2018-07-25 01:39:02 +08:00
}
void MainWindow : : ThreadOutput ( TextThread * thread , QString output )
{
2018-07-26 01:46:59 +08:00
if ( ttCombo - > currentText ( ) . startsWith ( TextThreadString ( thread ) ) )
{
textOutput - > moveCursor ( QTextCursor : : End ) ;
textOutput - > insertPlainText ( output ) ;
textOutput - > moveCursor ( QTextCursor : : End ) ;
}
2018-07-24 13:57:54 +08:00
}
2018-08-23 03:11:40 +08:00
QString MainWindow : : TextThreadString ( TextThread * thread )
{
2018-08-23 23:53:23 +08:00
ThreadParam tp = thread - > GetThreadParam ( ) ;
2018-08-23 03:11:40 +08:00
return QString ( " %1:%2:%3:%4: " ) . arg (
QString : : number ( tp . pid ) ,
QString : : number ( tp . hook , 16 ) ,
QString : : number ( tp . retn , 16 ) ,
QString : : number ( tp . spl , 16 )
) . toUpper ( ) ;
}
2018-08-23 23:53:23 +08:00
ThreadParam MainWindow : : ParseTextThreadString ( QString textThreadString )
2018-08-23 03:11:40 +08:00
{
QStringList threadParam = textThreadString . split ( " : " ) ;
return { threadParam [ 0 ] . toUInt ( ) , threadParam [ 1 ] . toULongLong ( nullptr , 16 ) , threadParam [ 2 ] . toULongLong ( nullptr , 16 ) , threadParam [ 3 ] . toULongLong ( nullptr , 16 ) } ;
}
DWORD MainWindow : : GetSelectedProcessId ( )
{
return processCombo - > currentText ( ) . split ( " : " ) [ 0 ] . toULong ( ) ;
}
2018-08-18 02:37:37 +08:00
void MainWindow : : ReloadExtensions ( )
{
extenCombo - > clear ( ) ;
std : : map < int , QString > extensions = LoadExtensions ( ) ;
for ( auto i : extensions ) extenCombo - > addItem ( QString : : number ( i . first ) + " : " + i . second ) ;
}
2018-08-04 15:16:14 +08:00
std : : unordered_map < std : : string , int > MainWindow : : GetInfoForExtensions ( TextThread * thread )
{
return
{
2018-08-22 10:43:30 +08:00
{ " current select " , ( int ) ttCombo - > currentText ( ) . startsWith ( TextThreadString ( thread ) ) } ,
{ " text number " , 0 } ,
2018-08-23 23:53:23 +08:00
{ " process id " , thread - > GetThreadParam ( ) . pid } ,
{ " hook address " , ( int ) thread - > GetThreadParam ( ) . hook } ,
2018-09-01 16:23:29 +08:00
{ " hook address (upper 32 bits) " , ( int ) ( thread - > GetThreadParam ( ) . hook > > 32 ) } ,
{ " text handle " , ( int ) thread }
2018-08-04 15:16:14 +08:00
} ;
}
2018-07-26 12:48:18 +08:00
QVector < HookParam > MainWindow : : GetAllHooks ( DWORD processId )
{
2018-08-23 03:11:40 +08:00
QSet < DWORD > addresses ;
2018-07-26 12:48:18 +08:00
QVector < HookParam > hooks ;
for ( int i = 0 ; i < ttCombo - > count ( ) ; + + i )
2018-08-22 10:43:30 +08:00
{
2018-08-23 23:53:23 +08:00
ThreadParam tp = ParseTextThreadString ( ttCombo - > itemText ( i ) ) ;
2018-08-23 03:11:40 +08:00
if ( tp . pid = = processId & & ! addresses . contains ( tp . hook ) )
2018-07-26 12:48:18 +08:00
{
2018-08-22 10:43:30 +08:00
addresses . insert ( tp . hook ) ;
hooks . push_back ( Host : : GetHookParam ( tp ) ) ;
2018-07-26 12:48:18 +08:00
}
2018-08-22 10:43:30 +08:00
}
2018-07-26 12:48:18 +08:00
return hooks ;
}
2018-07-24 03:25:02 +08:00
void MainWindow : : on_attachButton_clicked ( )
2018-07-23 07:53:51 +08:00
{
2018-08-21 02:30:50 +08:00
std : : unordered_map < std : : wstring , DWORD > allProcesses = GetAllProcesses ( ) ;
QStringList processList ;
for ( auto i : allProcesses )
processList . push_back ( QString : : fromStdWString ( i . first ) ) ;
processList . sort ( Qt : : CaseInsensitive ) ;
2018-07-26 12:48:18 +08:00
bool ok ;
2018-07-31 11:25:08 +08:00
QString process = QInputDialog : : getItem ( this , " Select Process " ,
2018-08-19 03:06:14 +08:00
" If you don't see the process you want to inject, try running with admin rights \r \n You can just type in the process id if you know it " ,
2018-08-21 02:30:50 +08:00
processList , 0 , true , & ok ) ;
2018-07-31 11:25:08 +08:00
if ( ! ok ) return ;
2018-08-21 02:30:50 +08:00
if ( process . toInt ( ) )
{
if ( Host : : InjectProcess ( process . toInt ( ) ) ) return ;
}
else if ( Host : : InjectProcess ( allProcesses [ process . toStdWString ( ) ] ) ) return ;
2018-08-23 03:11:40 +08:00
Host : : AddConsoleOutput ( L " failed to attach " ) ;
2018-07-24 13:57:54 +08:00
}
void MainWindow : : on_detachButton_clicked ( )
{
2018-08-22 10:43:30 +08:00
Host : : DetachProcess ( GetSelectedProcessId ( ) ) ;
2018-07-24 13:57:54 +08:00
}
2018-07-26 12:48:18 +08:00
void MainWindow : : on_hookButton_clicked ( )
{
bool ok ;
2018-08-05 06:01:59 +08:00
QString hookCode = QInputDialog : : getText ( this , " Add Hook " , CodeInfoDump , QLineEdit : : Normal , " " , & ok ) ;
2018-07-31 11:25:08 +08:00
if ( ! ok ) return ;
2018-08-25 02:24:46 +08:00
if ( auto hp = ParseCode ( hookCode ) ) Host : : InsertHook ( GetSelectedProcessId ( ) , hp . value ( ) ) ;
else Host : : AddConsoleOutput ( L " invalid code " ) ;
2018-07-26 12:48:18 +08:00
}
void MainWindow : : on_unhookButton_clicked ( )
{
2018-08-22 10:43:30 +08:00
QVector < HookParam > hooks = GetAllHooks ( GetSelectedProcessId ( ) ) ;
2018-08-24 03:28:40 +08:00
if ( hooks . size ( ) = = 0 )
{
Host : : AddConsoleOutput ( L " no hooks detected " ) ;
return ;
}
2018-07-26 12:48:18 +08:00
QStringList hookList ;
for ( auto i : hooks ) hookList . push_back (
2018-08-22 10:43:30 +08:00
QString : : fromStdWString ( Host : : GetHookName ( GetSelectedProcessId ( ) , i . address ) ) +
2018-07-26 12:48:18 +08:00
" : " +
2018-08-22 10:43:30 +08:00
GenerateCode ( i , GetSelectedProcessId ( ) )
2018-07-26 12:48:18 +08:00
) ;
bool ok ;
QString hook = QInputDialog : : getItem ( this , " Unhook " , " Which hook to remove? " , hookList , 0 , false , & ok ) ;
2018-08-22 10:43:30 +08:00
if ( ok ) Host : : RemoveHook ( GetSelectedProcessId ( ) , hooks . at ( hookList . indexOf ( hook ) ) . address ) ;
2018-07-26 12:48:18 +08:00
}
2018-07-27 13:42:21 +08:00
void MainWindow : : on_saveButton_clicked ( )
{
2018-08-22 10:43:30 +08:00
QVector < HookParam > hooks = GetAllHooks ( GetSelectedProcessId ( ) ) ;
QString hookList = GetFullModuleName ( GetSelectedProcessId ( ) ) ;
2018-07-27 13:42:21 +08:00
for ( auto i : hooks )
if ( ! ( i . type & HOOK_ENGINE ) )
2018-08-22 10:43:30 +08:00
hookList + = " , " + GenerateCode ( i , GetSelectedProcessId ( ) ) ;
2018-07-27 13:42:21 +08:00
QFile file ( " SavedHooks.txt " ) ;
if ( ! file . open ( QIODevice : : Append | QIODevice : : Text ) ) return ;
file . write ( ( hookList + " \r \n " ) . toUtf8 ( ) ) ;
}
2018-07-24 13:57:54 +08:00
void MainWindow : : on_ttCombo_activated ( int index )
{
2018-08-22 10:43:30 +08:00
textOutput - > setPlainText ( QString : : fromStdWString ( Host : : GetThread ( ParseTextThreadString ( ttCombo - > itemText ( index ) ) ) - > GetStore ( ) ) ) ;
2018-07-26 01:46:59 +08:00
textOutput - > moveCursor ( QTextCursor : : End ) ;
2018-07-23 07:53:51 +08:00
}
2018-07-27 13:42:21 +08:00
void MainWindow : : on_addExtenButton_clicked ( )
{
2018-08-03 12:07:25 +08:00
QString extenFileName = QFileDialog : : getOpenFileName ( this , " Select Extension dll " , " C: \\ " , " Extensions (*.dll) " ) ;
2018-08-26 05:08:45 +08:00
if ( ! extenFileName . size ( ) ) return ;
2018-07-29 03:41:21 +08:00
QString extenName = extenFileName . split ( " / " ) [ extenFileName . split ( " / " ) . count ( ) - 1 ] ;
2018-08-26 05:08:45 +08:00
QString copyTo = QString : : number ( extenCombo - > itemText ( extenCombo - > count ( ) - 1 ) . split ( " : " ) [ 0 ] . toInt ( ) + 1 ) + " _ " + extenName ;
2018-07-29 03:41:21 +08:00
QFile : : copy ( extenFileName , copyTo ) ;
2018-08-18 02:37:37 +08:00
ReloadExtensions ( ) ;
2018-07-29 03:41:21 +08:00
}
void MainWindow : : on_rmvExtenButton_clicked ( )
{
2018-08-03 12:07:25 +08:00
if ( extenCombo - > currentText ( ) . size ( ) = = 0 ) return ;
2018-08-26 05:08:45 +08:00
QString extenFileName = extenCombo - > currentText ( ) . split ( " : " ) [ 0 ] + " _ " + extenCombo - > currentText ( ) . split ( " : " ) [ 1 ] + " .dll " ;
2018-07-29 03:41:21 +08:00
FreeLibrary ( GetModuleHandleW ( extenFileName . toStdWString ( ) . c_str ( ) ) ) ;
2018-08-20 05:55:50 +08:00
QFile : : remove ( extenFileName ) ;
2018-08-18 02:37:37 +08:00
ReloadExtensions ( ) ;
2018-07-27 13:42:21 +08:00
}