Προς το περιεχόμενο

c++: Δημιουργια exe μεσα απο exe


Axelfc

Προτεινόμενες αναρτήσεις

Δημοσ.

Αυτο που θελω να κανω ειναι ενα προγραμμα το οποιο οταν θα εκτελειται θα βγαζει ενα μηνυμα στην οθονη και συγχρονως θα δημιουργει ενα καινουργιο αρχειο exe. Οταν κλεισω το πρωτο προγραμμα και εκτελεσω το δευτερο θελω αυτο με τη σειρα του να βγαζει ενα αλλο μηνυμα.

 

Το προβλημα ειναι πως με τον παρακατω κωδικα που εχω γραψει και τα δυο προγραμματα τυπωνουν και τα δυο μηνυματα. Ξερει κανεις αν/πως μπορει να γινει αυτο που ψαχνω?

 

Γενικοτερα μπορω με καποιο τροπο να ορισω τις εντολες που θελω να εκτελουνται απο το πρωτο προγραμμα και τις εντολες που θα εκτελουνται απο το δευτερο?

 

Οριστε και ο κωδικας

 

>
#include <windows.h>
#include <iostream.h>

void main() {
cout << "1: Initial program...\n";

char currentDir[MAX_PATH];
char pathtofile[MAX_PATH];
HMODULE GetModH = GetModuleHandle(NULL);
GetModuleFileName(GetModH,pathtofile,sizeof(pathtofile));
GetCurrentDirectory(MAX_PATH,currentDir);
strcat(currentDir,"\\newProgram.exe");
cout << "2: newProgram\n";
CopyFile(pathtofile,currentDir,false);

cout << "Press enter to close...\n";
cin.get();

}

Δημοσ.

Δεν είμαι σίγουρος τι προσπαθείς να κάνεις ..

 

Για παράδειγμα, θέλεις να περάσεις κάποιες παραμέτρους στο αντίγραφο του εαυτού σου ώστε να καταλάβει πως έχει μπει σε δεύτερη φάση εκτέλεσης (το θέτω όπως-όπως καταλαβαίνεις τι εννοώ ;)) - αν ναι, δες την ShellExecute ή ShellExecuteEx ώστε να τις περάσεις και συνάμα άλλαξε το main σε main(int argc,char *argv[]) για να τις πιάσεις (μιας και το πρόγραμμα σου είναι Console δεν υπάρχει λόγος για άλλες WinAPI κλήσεις επ' αυτού του τελευταίου).

 

Τώρα αν θες κάτι διαφορετικό γίνεται πιο συγκεκριμένος..

Δημοσ.

Εάν κατάλαβα καλά αυτό που χρειάζεσαι είναι να δημιουργείς ένα αρχείο .cpp και έπειτα στο run time να μπορείς να το κάνεις compile το αρχείο έτσι ώστε να δημιουργήσεις το .exe.

Οπότε αρχικά δημιουργείς το αρχείο .cpp και πετάς μέσα τον κώδικα τον κώδικα του 2ου προγράμματος.

Για παράδειγμα.

 

AnsiString Temp=”#include<stdio.h> void main(void){ printf(“oeo”); getch()}”;

FILE *fp;

fp=fopen(“sanidas.cpp”,w);

fprintf(fp,”%s”,Temp);

fclose(fp);

 

Έπειτα υπάρχει το σετ εντολών exec (execl,execv κτλ)που μπορείς να καλέσεις εξωτερικά applications. Για να κάνεις compile το sanidas.cpp πρέπει να καλέσεις την εντολή BCC32. Περισσότερες πληροφορίες για το BCC32 θα βρεις στο help της builder στα Command-line tools

Δημοσ.

Ουσιαστικά, θέλεις να αλλάξεις τα static data ενός αντιγράφου του εκτελέσιμού σου. Αυτό προϋποθέτει να δημιουργήσεις έναν binary parser που θα ψάχνει σε εκτελέσιμα για το αντίστοιχο μέρος των static data, θα αλλάζει το string και τα offset σε περίπτωση που έχεις και άλλα αντικείμενα στον static χώρο.

 

Πχ, στον κώδικα αν κάνεις cout << "Hello" << a << "there"; και προσπαθήσεις να αλλάξεις το "Hello" σε κάτι άλλο, πρέπει να αλλάξεις και κάθε reference στο "there" αφού στον static χώρο εμφανίζονται σαν Hello\0there\0 και στις συναρτήσεις δίνονται διευθύνσεις. Κάτι τέτοιο δεν είναι απλό.

Δημοσ.

Ας εξηγησω λιγο αναλυτικοτερα αυτο που προσπαθω να κανω. Εχω τον κωδικα του 1ου μου post, ας πουμε με ονομα initialProgram.cpp. Το κανω compile και το τρεχω. Τοτε θα εκτυπωθουν στην οθονη τα δυο cout και συγχρονως θα δημιουργηθει στον τρεχον φακελο ενα καινουργιο αρχειο με ονομα newProgram.exe. Τερματιζω το initialProgram.exe και τρεχω το καινουργιο newProgram.exe. Αυτο με τη σειρα του θα εκτυπωσει τα παραπανω δυο cout.

 

Αυτο που θελω να κανω, (δεν ξερω καν αν γινεται, δεν βρηκα κατι και στο google γι'αυτο ρωταω εδω) ειναι το initialProgram.exe να εκτυπωνει μονο το 1ο cout και να δημιουργει το newProgram.exe ενσωματωνοντας του το 2ο cout ωστε να εκτελεστει οταν τρεξω το καινουργιο προγραμμα.

 

Δεν εχει να κανει δλδ με χρηση αρχειων, fopen, η κληση εξωτερικων προγραμματων, shellExecute.

 

Ισως αυτο που λεει ο dop να εχει καποια σχεση, αν καταλαβα καλα.

 

Ευχαριστω για τις απαντησεις οπως και να εχει.

Δημοσ.

Θα πρέπει να αλλάξει όχι μόνο τα static data αλλά να ξεφωρτοθείς και το άχρηστο δεύτερο cout σαν κλήση, οπότε ενδεχομένως θα πρέπει να επέμβεις στον κώδικα μηχανής της εφαρμογής -δεν είναι ιδιαίτερα δύσκολο (αν ακολουθήσεις ορισμένες συμβάσεις στην αρχική σχεδίαση) αλλά μπελαλίδικο..

Δημοσ.

Ίσως να μπορέσεις να το κάνεις, αν δημιουργήσεις κάτι σαν:

 

>
bool j = true;
if (j)
// call something
else
// call something else

και να πείσεις τον compiler να μην το κάνει optimize - χρησιμοποιώντας volatile, κάνοντας compile με επιπλέον debugging πληροφορίες κλπ.

 

Έπειτα απλώς θα αλλάξεις την τιμή σε false. Και πάλι όμως μπλέκεις με κώδικα μηχανής.

 

@DirectX: αν βάλει ένα απλό jump, τελείωσε, δεν χρειάζεται να σβήσει κάτι. ΑΛΛΑ, πρέπει να αλλάξει όλες τις σχετικές διευθύνσεις μνήμης μέσα στο πρόγραμμα.

Δημοσ.

Βρεθηκε η λυση, περιπου οπως λες dop. Απλως κανω εναν ελεγχο αν το ονομα του προγραμματος που τρεχει ειναι το initial η το new και εκτελω αναλογα τον κωδικα που θελω.

 

Οριστε και ο πηγαιος.

 

>
#include <windows.h>
#include <iostream.h>

int main() {
char currentDir[MAX_PATH];
char pathtofile[MAX_PATH];
HMODULE GetModH = GetModuleHandle(NULL);
GetModuleFileName(GetModH,pathtofile,sizeof(pathtofile));


if ( strstr( pathtofile, "newProgram.exe" ) != NULL ) {
  // be the new program
  cout << "2: newProgram!\n";

  cout << "Press enter to close...\n";
  cin.get();
} else {
  // be the old program
  cout << "1: Initial program...\n";

  GetCurrentDirectory(MAX_PATH,currentDir);
  strcat(currentDir,"\\newProgram.exe");
  CopyFile(pathtofile,currentDir,false);

  cout << "Press enter to close...\n";
  cin.get();
}
}

 

Ευχαριστω ολους για τις απαντησεις!

Δημοσ.

@DirectX: αν βάλει ένα απλό jump, τελείωσε, δεν χρειάζεται να σβήσει κάτι. ΑΛΛΑ, πρέπει να αλλάξει όλες τις σχετικές διευθύνσεις μνήμης μέσα στο πρόγραμμα.

 

Πιο συμφέρουσες λοιπόν μερικές nop ;)

Δημοσ.

Το παρακάτω ενδεικτικό πρόγραμμα, γραμμένο σε Borland C/C++ Builder 6, αντιγράφει τον εαυτό του σε ένα νέο εκτελέσιμο (newProgam.exe) στο τρέχον κατάλογο και ύστερα επεμβαίνει στα δεδομένα της μεταβλητής szLine_A όπου αντικαθιστά τον πρώτο χαρακτήρα αλλαγής γραμμής (\n) με κενό του νέου αντίγραφου.

Ύστερα σε δεύτερη φάση αλλάζει τον κώδικα !bSecond_Generation προσπερνώντας όλες τις προηγούμενες ρουτίνες ως το cout ομοίως.

Ο λόγος που απλά δεν άλλαξα την default τιμή της bSecond_Generation είναι για να επιδειχθεί η αλλαγή του assembled κώδικα.

 

>
//-SELF MODIFY -STATIC & CODE PARTS------------------------------------------
#include <windows.h>
#include <iostream>
#pragma hdrstop

using namespace std;

#define  DATA_OFFSET 0x14B2
#define  CODE_OFFSET 0x788
//---------------------------------------------------------------------------
char  szLine_A[100] = "This is line 1\nThis is line 2",
     szDestination[MAX_PATH];

BYTE  byCode  [6] = { 0xE9, 0xB5, 0, 0, 0, 0x90 },
     byStatic[1] = { ' ' };

bool  bSecond_Generation = false;
//---------------------------------------------------------------------------
void _SelfModify(char *pszDestination,DWORD dwOffset,BYTE *pszNewData,DWORD dwLen);
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
  try
   {
     if(!bSecond_Generation)       
      {
        // Get current directory
        if(!GetCurrentDirectory(MAX_PATH,szDestination))
         throw (char*)"Cannot find current directory!";

        // Build Destination path
        lstrcat(szDestination,"\\newProgram.exe");

        // Copy ourself to newProgram.exe
        if(!CopyFile(argv[0],szDestination,FALSE))
         throw (char*)"Cannot create destination executable!";

        // Apply changes to cout static data for second file version (or copy)
        _SelfModify(szDestination,DATA_OFFSET,byStatic,sizeof(byStatic));

        // Change execution flow for newProgram.exe so it won't CopyFile..
        _SelfModify(szDestination,CODE_OFFSET,byCode,sizeof(byCode));
      }

     // Print out Lines
     cout << szLine_A << endl;
   }
  catch(char* pszError)
   {
     cout << "Exception:" << pszError << endl;
   }

  return 0;
}
//---------------------------------------------------------------------------
void  _SelfModify(char *pszDestination,DWORD dwOffset,BYTE *pszNewData,DWORD dwLen)
{
  HANDLE   hIO = INVALID_HANDLE_VALUE;
  DWORD    dwWrittenBytes;

  try
   {
     // 1st] Open pszDestination for Read/Write
     if((hIO=CreateFile(pszDestination,GENERIC_READ|GENERIC_WRITE,
                        0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,
                        NULL))==INVALID_HANDLE_VALUE)
      throw (char*)"Cannot open destination file for read/write!";

     // 2nd] Check Offset validity
     if(GetFileSize(hIO,NULL)<dwOffset)
      throw (char*)"Invalid destination file offset!";

     // 3rd] Seek Destination offset for manipulation
     if(SetFilePointer(hIO,dwOffset,NULL,FILE_BEGIN)==0xFFFFFFFF)
      throw (char*)"Unable to seek destination file offset!";

     // 4th] Modify static data
     if(!WriteFile(hIO,pszNewData,dwLen,&dwWrittenBytes,NULL))
      throw (char*)"Cannot write destination file modified data!";
   }
  __finally
   {
     // Either case get rid of CreateFile stream
     CloseHandle(hIO);
   }
}

 

Οι θέσεις μνήμης μεταβλητής και κώδικα, όσο και το μέγεθος των αρχικών op'codes, φυσικά μπορεί να διαφέρουν με βάση τις ρυθμίσεις του C/C++ Builder Compiler/IDE σας (για dis-assembling προτείνω τον IDA freeware edition) -φυσικά αν έχουμε κέφια μπορούμε να γράψουμε ρουτίνες αυτόματου εντοπισμού τους λίγο πολύ σίγουρες.

 

Τέλος ευτύχημα αποτελεί πως η οργάνωση του κώδικα σε 32bit εκτελέσιμα Windows (PE) είναι τέτοια που επιτρέπει εύκολο patching στην πλειονότητα των περιπτώσεων.

 

Υ.Γ.

Φυσικά, το λογισμικό μπορεί να περιέχει bugs..

 

Καλή Πρωτοχρονιά σε όλους!

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...