Hi, ich hatte vor ein Programm zu schreiben, mit dem man den ausführbaren code einer ausführbaren Datei an eine andere hängt.
Z.B. um ne Passwortabfrage vorzuschieben. Außerdem wollte ich dann noch ne GUI zu schreiben.
Leider habe ich ein paar Probleme mit der grundsätzlichen Umsetzung. Ich kriege nen Pagefault bzw. nachdem ich den Charakterflag auf executable umgestellt habe eine "frame is not in stack limits".
Ich wäre froh wenn mir jemand helfen würde, das ding fertig zu machen. Bei fragen zum Code oder C Programmierung allgemein helfe ich generell auch gerne. Ich poste mal den Code und schreibe was er macht.
Funktionsweise ist:
den header wie ihn die PE_header struct darstellt einlesen (klappt)
dann den verändere ich die Werte wie folgt:
- errechne den entry point
- addiere den errechneten entry point mit der alten PE_header.VirtualSize
- erhöhe den SizeOfImage mit der größe des Anhängsels
- mache das gleiche mit der VirtualSize
- und mit der SizeOfRawData
- setze die characteristics auf executable
In diesem Fall möchte ich dass statt der Ausführung von Diablo^^ ein "Hello World" erscheint. Ich teste das btw. immer mit wine^^
Das sind ein paar Typen die ich erstellt habe, da ich unter Linux programmiere und kein DWORD und WORD zur verfügung steht. ich bin mir nicht sicher ob ihr wisst, was ein union ist. (alles in einem union teilt sich den selben speicher) Mit diesen Datentypen kann ich zb. ne zahl über das valu zuweisen und in den filebuffer über das bytearray schreiben. an sich ist das verdammt praktisch.
Dann habe ich noch den restlichen code. angeführt von ner funktion die die Datei einliest, noch nix besonderes:
Diese Funktion liest den bytecode durch und speichert die headerinformationen in die struct die ich oben definiert habe. ich habe die hex-werte mit intwerten ersetzt, damit ich über das array drauf zugreifen kann.
das hier ist wohl die kritische funktion, weil sie den header editieren muss, hier ind vermutlich die logischen fehler drin.
naja und der rest macht im prinzip folgendes:
-prepareTag soll die Section Table der exe auslesen
-addTag soll diese Tables anhängen
Z.B. um ne Passwortabfrage vorzuschieben. Außerdem wollte ich dann noch ne GUI zu schreiben.
Leider habe ich ein paar Probleme mit der grundsätzlichen Umsetzung. Ich kriege nen Pagefault bzw. nachdem ich den Charakterflag auf executable umgestellt habe eine "frame is not in stack limits".
Ich wäre froh wenn mir jemand helfen würde, das ding fertig zu machen. Bei fragen zum Code oder C Programmierung allgemein helfe ich generell auch gerne. Ich poste mal den Code und schreibe was er macht.
Funktionsweise ist:
den header wie ihn die PE_header struct darstellt einlesen (klappt)
dann den verändere ich die Werte wie folgt:
- errechne den entry point
- addiere den errechneten entry point mit der alten PE_header.VirtualSize
- erhöhe den SizeOfImage mit der größe des Anhängsels
- mache das gleiche mit der VirtualSize
- und mit der SizeOfRawData
- setze die characteristics auf executable
In diesem Fall möchte ich dass statt der Ausführung von Diablo^^ ein "Hello World" erscheint. Ich teste das btw. immer mit wine^^
Das sind ein paar Typen die ich erstellt habe, da ich unter Linux programmiere und kein DWORD und WORD zur verfügung steht. ich bin mir nicht sicher ob ihr wisst, was ein union ist. (alles in einem union teilt sich den selben speicher) Mit diesen Datentypen kann ich zb. ne zahl über das valu zuweisen und in den filebuffer über das bytearray schreiben. an sich ist das verdammt praktisch.
Code:
/*
* WORD
*/
union WORD {
unsigned short value;
char BYTE[2];
};
/*
* DWORD
*/
union DWORD {
unsigned long value;
char BYTE[4];
};
struct PE_HEAD {
DWORD HeaderAdress;
WORD NumberOfSections; // 06
DWORD AddressOfEntryPoint; // 28
DWORD OEP;
DWORD ImageBase; // 34
DWORD SizeOfImage; // 50
/*
* properties of last section required
*/
DWORD VirtualSize; // [PE+0xF8]+(NumberOfSections-1)*0x28 + 08
DWORD VirtualAddress; // [PE+0xF8]+(NumberOfSections-1)*0x28 + 0C
DWORD SizeOfRawData; // [PE+0xF8]+(NumberOfSections-1)*0x28 + 10
DWORD Characteristics; // [PE+0xF8]+(NumberOfSections-1)*0x28 + 24
};
Dann habe ich noch den restlichen code. angeführt von ner funktion die die Datei einliest, noch nix besonderes:
Code:
/*
* reads the file binary
*/
inline unsigned long readFile(char* pathToFile, char* &byteArray){
/*
* open file
*/
FILE *fin = fopen(pathToFile, "r");
if (fin == NULL)
return false;
/*
* get file size
*/
struct stat buf;
stat(pathToFile, &buf);
unsigned int fileSize = buf.st_size;
//and allocate memory
byteArray = new char[fileSize];
/*
* readfile now
*/
fread(byteArray, sizeof(char), fileSize, fin);
fclose(fin);
return fileSize;
}
Code:
/*
* seek for offsets
* modify global variables
*
* return some header stuff via function argument
* returns the position of the PE header via return
*/
inline DWORD parseFile(const char* byteArray, unsigned long sizeOfArray, PE_HEAD &header) {
DWORD header_adress;
/*
* PE OFFSET
* PE offset is allways at 3C == 60dez
*/
memcpy(header_adress.BYTE, byteArray+60, 4);
/*
* SECTIONS OFFSET
* 06 == 6dez after PE entry point
*/
memcpy(header.NumberOfSections.BYTE, byteArray+header_adress.value+6, 2);
/*
* ENTRY POINT OFFSET
* 28 == 40dez after PE entry point
*/
memcpy(header.AddressOfEntryPoint.BYTE, byteArray+header_adress.value+40, 4);
/*
* ENTRY POINT OFFSET
* 32 == 52dez after PE entry point
*/
memcpy(header.ImageBase.BYTE, byteArray+header_adress.value+52, 4);
header.OEP.value = header.AddressOfEntryPoint.value + header.ImageBase.value;
/*
* IMAGE SIZE
* 50 == 80dez after PE entry point
*/
memcpy(header.SizeOfImage.BYTE, byteArray+header_adress.value+80, 4);
/*
* PROPERTIES OF LAST SECTION
* [PE+0xF8]+(NumberOfSections-1)*0x28
*/
memcpy( header.VirtualSize.BYTE,
byteArray+(header_adress.value+248+(header.NumberOfSections.value-1)*40) + 8, 4);
memcpy( header.VirtualAddress.BYTE,
byteArray+(header_adress.value+248+(header.NumberOfSections.value-1)*40) + 12, 4);
memcpy( header.SizeOfRawData.BYTE,
byteArray+(header_adress.value+248+(header.NumberOfSections.value-1)*40) + 16, 4);
memcpy( header.Characteristics.BYTE,
byteArray+(header_adress.value+248+(header.NumberOfSections.value-1)*40) + 36, 4);
header.HeaderAdress = header_adress;
return header_adress;
}
das hier ist wohl die kritische funktion, weil sie den header editieren muss, hier ind vermutlich die logischen fehler drin.
Code:
/*
* overwrites the old entrys with new ones
* deltaSize == size of NEW code
*/
inline void modHeaderProperties(char* &byteArray, PE_HEAD PE_header,
/*DWORD newEntryPnt,*/ unsigned long deltaSize)
{
unsigned long m_lTmp;
DWORD m_dTmp;
DWORD header_adress = PE_header.HeaderAdress;
/*
* ENTRY POINT OFFSET
* 28 == 40dez after PE entry point
*/
m_dTmp.value = PE_header.OEP.value + PE_header.VirtualSize.value;
memcpy(byteArray+header_adress.value+40, m_dTmp.BYTE, 4);
/*
* IMAGE SIZE
* 50 == 80dez after PE entry point
*/
m_dTmp.value = PE_header.SizeOfImage.value + deltaSize;
memcpy(byteArray+header_adress.value+80, m_dTmp.BYTE, 4);
/*
* PROPERTIES OF LAST SECTION
* [PE+0xF8]+(NumberOfSections-1)*0x28
*/
m_dTmp.value = PE_header.VirtualSize.value + deltaSize;
memcpy( byteArray+(PE_header.HeaderAdress.value+248+(PE_header.NumberOfSections.value-1)*40) + 8,
m_dTmp.BYTE, 4);
/*
* last section begin
*/
/*
m_lTmp = PE_header.HeaderAdress.value+248+(PE_header.NumberOfSections.value-1)*40;
m_dTmp.value = m_lTmp;
memcpy( byteArray+(PE_header.HeaderAdress.value+248+(PE_header.NumberOfSections.value-1)*40) + 12,
m_dTmp.BYTE, 4);
*/
m_lTmp = PE_header.SizeOfRawData.value + deltaSize;
m_dTmp.value = m_lTmp;
memcpy( byteArray+(PE_header.HeaderAdress.value+248+(PE_header.NumberOfSections.value-1)*40) + 16,
m_dTmp.BYTE, 4);
m_dTmp.value = 140000020;
memcpy( byteArray+(PE_header.HeaderAdress.value+248+(PE_header.NumberOfSections.value-1)*40) + 36,
m_dTmp.BYTE, 4);
}
naja und der rest macht im prinzip folgendes:
-prepareTag soll die Section Table der exe auslesen
-addTag soll diese Tables anhängen
Code:
/*
* parse and cleave a file whicht will get insertet
* to the file which will get injected
*/
inline unsigned long prepareTag(char* pathToFile, char* &byteArray) {
char *buffer;
int size = readFile(pathToFile, buffer);
/*
* look for entry point
*/
PE_HEAD header;
parseFile(buffer, size, header);
unsigned long begOfSecs = header.HeaderAdress.value + 248;
/*
* delete all before of the entry point
* i think we shouldn't need this shit
*/
int new_size = size - begOfSecs;
byteArray = new char[new_size];
memcpy(byteArray, buffer+begOfSecs, new_size);
return new_size;
}
/*
* modifies the jump adress
* set to end of file or something
*
* returns the modded file via function argument
*/
inline unsigned long addTag( const char* byteArray, unsigned long sizeA,
const char* modByteArray, unsigned long sizeM,
char* &editedFile) {
editedFile = new char[sizeA+sizeM];
/*
* load base file into buffer an appen moded file
*/
memcpy(editedFile, byteArray, sizeA);
memcpy(editedFile+sizeA, modByteArray, sizeM);
return sizeA+sizeM;
}
int main(void) {
PE_HEAD header;
char *buffer_base, *buffer_add, *buffer_inj;
unsigned long size_base, size_add;
size_base = readFile("diablo.exe", buffer_base); //reads the file and save to buffer
parseFile(buffer_base, size_base, header); //looks for PE header
//cout<<"entry point before: "<<header.AddressOfEntryPoint.value<<endl;
size_add = readFile("hallo.exe", buffer_add); //prepares other file for injections
unsigned long new_ln = addTag(buffer_base, size_base, buffer_add, size_add, buffer_inj);
modHeaderProperties(buffer_inj, header, size_add);
//parseFile(buffer_inj, new_ln, header);
//cout<<"entry point after: "<<header.AddressOfEntryPoint.value<<endl;
/*
* write new file
*/
FILE *fout = fopen("inf.exe", "w");
if (fout == NULL)
return false;
fwrite(buffer_inj, sizeof(char), new_ln, fout);
fclose(fout);
return EXIT_SUCCESS;
}