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-09-22 10:25:37 +08:00
if ( settings . contains ( " Window " ) ) this - > setGeometry ( settings . value ( " Window " ) . toRect ( ) ) ;
2018-09-24 10:29:33 +08:00
// TODO: add GUI for changing these
2018-10-09 14:09:52 +08:00
if ( settings . contains ( " Flush_Delay " ) ) TextThread : : flushDelay = settings . value ( " Flush_Delay " ) . toInt ( ) ;
if ( settings . contains ( " Max_Buffer_Size " ) ) TextThread : : maxBufferSize = settings . value ( " Max_Buffer_Size " ) . toInt ( ) ;
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 ) ;
2018-10-18 05:38:05 +08:00
ReloadExtensions ( ) ;
2018-08-22 10:43:30 +08:00
Host : : Start (
[ & ] ( DWORD processId ) { emit SigAddProcess ( processId ) ; } ,
[ & ] ( DWORD processId ) { emit SigRemoveProcess ( processId ) ; } ,
[ & ] ( TextThread * thread ) { emit SigAddThread ( thread ) ; } ,
2018-10-08 12:26:43 +08:00
[ & ] ( TextThread * thread ) { emit SigRemoveThread ( thread ) ; } ,
[ & ] ( TextThread * thread , std : : wstring & output ) { return ProcessThreadOutput ( thread , output ) ; }
2018-08-22 10:43:30 +08:00
) ;
2018-10-18 05:38:05 +08:00
Host : : AddConsoleOutput ( L " Textractor beta v3.3.1 by Artikash \r \n Source code and more information available under GPLv3 at https://github.com/Artikash/Textractor " ) ;
2018-07-22 06:40:16 +08:00
}
MainWindow : : ~ MainWindow ( )
{
2018-09-22 10:25:37 +08:00
settings . setValue ( " Window " , this - > geometry ( ) ) ;
2018-10-09 14:09:52 +08:00
settings . setValue ( " Flush_Delay " , TextThread : : flushDelay ) ;
settings . setValue ( " Max_Buffer_Size " , TextThread : : maxBufferSize ) ;
2018-09-22 10:25:37 +08:00
settings . sync ( ) ;
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-10-08 12:26:43 +08:00
void MainWindow : : AddProcess ( unsigned processId )
2018-07-24 13:57:54 +08:00
{
2018-09-23 05:13:06 +08:00
processCombo - > addItem ( QString : : number ( processId , 16 ) . toUpper ( ) + " : " + GetModuleName ( processId ) ) ;
2018-07-27 13:42:21 +08:00
QFile file ( " SavedHooks.txt " ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) return ;
QString processName = GetFullModuleName ( processId ) ;
2018-10-10 20:16:14 +08:00
QStringList allProcesses = QString ( file . readAll ( ) ) . split ( " \r " , QString : : SkipEmptyParts ) ;
for ( auto hooks = allProcesses . rbegin ( ) ; hooks ! = allProcesses . rend ( ) ; + + hooks )
if ( hooks - > contains ( processName ) )
2018-07-27 13:42:21 +08:00
{
2018-10-10 20:16:14 +08:00
for ( auto hook : hooks - > split ( " , " ) )
if ( auto hp = ParseCode ( hook ) ) Host : : InsertHook ( processId , hp . value ( ) ) ;
2018-07-27 13:42:21 +08:00
return ;
}
2018-07-24 13:57:54 +08:00
}
2018-10-08 12:26:43 +08:00
void MainWindow : : RemoveProcess ( unsigned processId )
2018-07-24 13:57:54 +08:00
{
2018-09-23 05:13:06 +08:00
processCombo - > removeItem ( processCombo - > findText ( QString : : number ( processId , 16 ) . toUpper ( ) + " : " , 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-09-21 10:32:47 +08:00
QString : : fromStdWString ( thread - > name ) +
2018-07-26 12:48:18 +08:00
" ( " +
2018-09-21 10:32:47 +08:00
GenerateCode ( Host : : GetHookParam ( thread - > tp ) , thread - > tp . pid ) +
2018-07-26 12:48:18 +08:00
" ) "
2018-07-26 01:46:59 +08:00
) ;
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-10-08 12:26:43 +08:00
bool MainWindow : : ProcessThreadOutput ( TextThread * thread , std : : wstring & output )
{
if ( DispatchSentenceToExtensions ( output , GetInfoForExtensions ( thread ) ) )
{
output + = L " \r \n " ;
emit SigThreadOutput ( thread , QString : : fromStdWString ( output ) ) ;
return true ;
}
return false ;
}
2018-08-23 03:11:40 +08:00
QString MainWindow : : TextThreadString ( TextThread * thread )
{
2018-09-21 10:32:47 +08:00
ThreadParam tp = thread - > tp ;
2018-09-22 10:25:37 +08:00
return QString ( " %1:%2:%3:%4:%5: " ) . arg (
2018-09-23 05:13:53 +08:00
QString : : number ( thread - > handle , 16 ) ,
2018-09-23 05:13:06 +08:00
QString : : number ( tp . pid , 16 ) ,
2018-08-23 03:11:40 +08:00
QString : : number ( tp . hook , 16 ) ,
QString : : number ( tp . retn , 16 ) ,
2018-09-23 05:13:06 +08:00
QString : : number ( tp . spl , 16 )
2018-08-23 03:11:40 +08:00
) . 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 ( " : " ) ;
2018-09-23 05:13:06 +08:00
return { threadParam [ 1 ] . toUInt ( nullptr , 16 ) , threadParam [ 2 ] . toULongLong ( nullptr , 16 ) , threadParam [ 3 ] . toULongLong ( nullptr , 16 ) , threadParam [ 4 ] . toULongLong ( nullptr , 16 ) } ;
2018-08-23 03:11:40 +08:00
}
DWORD MainWindow : : GetSelectedProcessId ( )
{
2018-09-23 05:13:06 +08:00
return processCombo - > currentText ( ) . split ( " : " ) [ 0 ] . toULong ( nullptr , 16 ) ;
2018-08-23 03:11:40 +08:00
}
2018-08-18 02:37:37 +08:00
void MainWindow : : ReloadExtensions ( )
{
extenCombo - > clear ( ) ;
2018-10-10 19:03:15 +08:00
for ( auto extension : LoadExtensions ( ) ) extenCombo - > addItem ( QString : : number ( extension . number ) + " : " + extension . name ) ;
2018-08-18 02:37:37 +08:00
}
2018-09-21 10:32:47 +08:00
std : : unordered_map < std : : string , int64_t > MainWindow : : GetInfoForExtensions ( TextThread * thread )
2018-08-04 15:16:14 +08:00
{
return
{
2018-09-23 05:13:06 +08:00
{ " current select " , ttCombo - > currentText ( ) . startsWith ( TextThreadString ( thread ) ) } ,
{ " text number " , thread - > handle } ,
2018-09-21 10:32:47 +08:00
{ " process id " , thread - > tp . pid } ,
2018-09-23 05:13:06 +08:00
{ " hook address " , thread - > tp . hook } ,
{ " text handle " , thread - > handle } ,
2018-09-21 10:32:47 +08:00
{ " text name " , ( int64_t ) thread - > name . c_str ( ) }
2018-08-04 15:16:14 +08:00
} ;
}
2018-07-26 12:48:18 +08:00
QVector < HookParam > MainWindow : : GetAllHooks ( DWORD processId )
{
2018-10-12 00:58:30 +08:00
QSet < uint64_t > 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-09-10 10:37:48 +08:00
QMultiHash < QString , DWORD > allProcesses = GetAllProcesses ( ) ;
QStringList processList ( allProcesses . uniqueKeys ( ) ) ;
2018-08-21 02:30:50 +08:00
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-10-12 03:06:44 +08:00
" If you don't see the process you want to inject, try running with admin rights \r \n You can also type in the process id " ,
2018-08-21 02:30:50 +08:00
processList , 0 , true , & ok ) ;
2018-09-13 23:59:15 +08:00
bool injected = false ;
2018-07-31 11:25:08 +08:00
if ( ! ok ) return ;
2018-09-13 23:59:15 +08:00
if ( process . toInt ( nullptr , 0 ) ) injected | = Host : : InjectProcess ( process . toInt ( nullptr , 0 ) ) ;
2018-10-10 20:16:14 +08:00
else for ( auto processId : allProcesses . values ( process ) ) injected | = Host : : InjectProcess ( processId ) ;
2018-09-13 23:59:15 +08:00
if ( ! injected ) Host : : AddConsoleOutput ( L " failed to inject " ) ;
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-10-19 10:52:27 +08:00
if ( hooks . empty ( ) ) return Host : : AddConsoleOutput ( L " no hooks detected " ) ;
2018-07-26 12:48:18 +08:00
QStringList hookList ;
2018-10-10 20:16:14 +08:00
for ( auto hook : hooks )
hookList . push_back (
2018-10-12 00:58:30 +08:00
QString : : fromStdWString ( Host : : GetHookName ( GetSelectedProcessId ( ) , hook . insertion_address ) ) +
2018-10-10 20:16:14 +08:00
" : " +
GenerateCode ( hook , 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-10-12 00:58:30 +08:00
if ( ok ) Host : : RemoveHook ( GetSelectedProcessId ( ) , hooks . at ( hookList . indexOf ( hook ) ) . insertion_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-10-10 20:16:14 +08:00
for ( auto hook : hooks )
if ( ! ( hook . type & HOOK_ENGINE ) )
hookList + = " , " + GenerateCode ( hook , 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-10-08 12:26:43 +08:00
textOutput - > setPlainText ( QString : : fromStdWString ( Host : : GetThread ( ParseTextThreadString ( ttCombo - > itemText ( index ) ) ) - > GetStorage ( ) ) ) ;
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-10-19 10:52:27 +08:00
if ( extenCombo - > currentText ( ) = = " " ) return ;
2018-10-17 13:08:31 +08:00
UnloadExtension ( extenCombo - > currentText ( ) . split ( " : " ) [ 0 ] . toInt ( ) ) ;
2018-08-18 02:37:37 +08:00
ReloadExtensions ( ) ;
2018-07-27 13:42:21 +08:00
}