2018-07-22 06:40:16 +08:00
# include "mainwindow.h"
# include "ui_mainwindow.h"
2018-11-01 08:09:29 +08:00
# include "defs.h"
2018-11-02 02:07:42 +08:00
# include "extenwindow.h"
2018-07-26 12:48:18 +08:00
# include "misc.h"
2018-08-23 03:11:40 +08:00
# include <QInputDialog>
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-11-01 22:38:14 +08:00
ui ( new Ui : : MainWindow ) ,
2018-11-02 02:07:42 +08:00
extenWindow ( new ExtenWindow )
2018-07-22 06:40:16 +08:00
{
2018-07-26 01:46:59 +08:00
ui - > setupUi ( this ) ;
2018-07-24 03:25:02 +08:00
2018-08-22 10:43:30 +08:00
processCombo = findChild < QComboBox * > ( " processCombo " ) ;
ttCombo = findChild < QComboBox * > ( " ttCombo " ) ;
textOutput = findChild < QPlainTextEdit * > ( " textOutput " ) ;
2018-10-28 14:27:24 +08:00
if ( settings . contains ( " Window " ) ) this - > setGeometry ( settings . value ( " Window " ) . toRect ( ) ) ;
// TODO: add GUI for changing these
2018-11-02 09:59:13 +08:00
if ( settings . contains ( " Default_Codepage " ) ) DEFAULT_CODEPAGE = settings . value ( " Default_Codepage " ) . toInt ( ) ;
2018-10-28 14:27:24 +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-10-31 13:20:44 +08:00
qRegisterMetaType < std : : shared_ptr < TextThread > > ( ) ;
2018-08-22 10:43:30 +08:00
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
2018-08-22 10:43:30 +08:00
Host : : Start (
[ & ] ( DWORD processId ) { emit SigAddProcess ( processId ) ; } ,
[ & ] ( DWORD processId ) { emit SigRemoveProcess ( processId ) ; } ,
2018-10-31 13:20:44 +08:00
[ & ] ( std : : shared_ptr < TextThread > thread ) { emit SigAddThread ( thread ) ; } ,
[ & ] ( std : : shared_ptr < TextThread > thread ) { emit SigRemoveThread ( thread ) ; } ,
2018-10-08 12:26:43 +08:00
[ & ] ( TextThread * thread , std : : wstring & output ) { return ProcessThreadOutput ( thread , output ) ; }
2018-08-22 10:43:30 +08:00
) ;
2018-11-02 09:32:18 +08:00
Host : : AddConsoleOutput ( L " Textractor beta v3.4.0 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-11-02 09:59:13 +08:00
settings . setValue ( " Default_Codepage " , DEFAULT_CODEPAGE ) ;
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-07-26 01:46:59 +08:00
delete ui ;
2018-11-01 00:04:32 +08:00
Host : : Close ( ) ;
2018-07-22 06:40:16 +08:00
}
2018-07-23 07:53:51 +08:00
2018-11-02 06:47:46 +08:00
void MainWindow : : closeEvent ( QCloseEvent * )
{
QCoreApplication : : quit ( ) ; // Need to do this to kill any windows that might've been made by extensions
}
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 " ) ;
2018-10-28 14:27:24 +08:00
file . open ( QIODevice : : ReadOnly ) ;
2018-07-27 13:42:21 +08:00
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-10-31 13:20:44 +08:00
void MainWindow : : AddThread ( std : : shared_ptr < TextThread > thread )
2018-07-24 13:57:54 +08:00
{
2018-07-26 01:46:59 +08:00
ttCombo - > addItem (
2018-10-31 13:20:44 +08:00
TextThreadString ( thread . get ( ) ) +
2018-09-21 10:32:47 +08:00
QString : : fromStdWString ( thread - > name ) +
2018-07-26 12:48:18 +08:00
" ( " +
2018-10-31 13:20:44 +08:00
GenerateCode ( thread - > hp , 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-10-31 13:20:44 +08:00
void MainWindow : : RemoveThread ( std : : shared_ptr < TextThread > thread )
2018-07-24 13:57:54 +08:00
{
2018-10-31 13:20:44 +08:00
int threadIndex = ttCombo - > findText ( TextThreadString ( thread . get ( ) ) , 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-07-25 01:39:02 +08:00
}
2018-10-31 13:20:44 +08:00
void MainWindow : : ThreadOutput ( QString threadString , QString output )
2018-07-25 01:39:02 +08:00
{
2018-10-31 13:20:44 +08:00
if ( ttCombo - > currentText ( ) . startsWith ( threadString ) )
2018-07-26 01:46:59 +08:00
{
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 )
{
2018-11-02 02:07:42 +08:00
if ( DispatchSentenceToExtensions ( output , GetMiscInfo ( thread ) ) )
2018-10-08 12:26:43 +08:00
{
output + = L " \r \n " ;
2018-10-31 13:20:44 +08:00
emit SigThreadOutput ( TextThreadString ( thread ) , QString : : fromStdWString ( output ) ) ;
2018-10-08 12:26:43 +08:00
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-11-02 02:07:42 +08:00
std : : unordered_map < std : : string , int64_t > MainWindow : : GetMiscInfo ( 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 " ) ;
2018-10-28 14:27:24 +08:00
file . open ( QIODevice : : Append ) ;
2018-07-27 13:42:21 +08:00
file . write ( ( hookList + " \r \n " ) . toUtf8 ( ) ) ;
}
2018-11-02 05:02:52 +08:00
void MainWindow : : on_extenButton_clicked ( )
2018-07-24 13:57:54 +08:00
{
2018-11-02 05:02:52 +08:00
extenWindow - > activateWindow ( ) ;
extenWindow - > showNormal ( ) ;
2018-07-23 07:53:51 +08:00
}
2018-07-27 13:42:21 +08:00
2018-11-02 05:02:52 +08:00
void MainWindow : : on_ttCombo_activated ( int index )
2018-07-27 13:42:21 +08:00
{
2018-11-02 05:02:52 +08:00
textOutput - > setPlainText ( QString : : fromStdWString ( Host : : GetThread ( ParseTextThreadString ( ttCombo - > itemText ( index ) ) ) - > GetStorage ( ) ) ) ;
textOutput - > moveCursor ( QTextCursor : : End ) ;
2018-07-27 13:42:21 +08:00
}