Bon le dernier article permettait de générer des fichier exe (PE). Lors de la compilation on passe généralement par des fichiers dit objet, que l’on « mix » ensemble grâce au linker. Sous Windows ce type de fichier a pour extension .obj et comme format COFF.
Pour generer un fichier d’exemple ont va utilisé le compilateur de Visual Studio, et compiler ce fichier :
int func(int a)
{
return a+1;
}
On compile avec la commande cl.exe /c sample.c, puis on peut dumper le fichier avec l’utilitaire microsoft dumpbin. dumpbin.exe /all sample.obj, ce qui nous donne:
File Type: COFF OBJECT
FILE HEADER VALUES
14C machine (x86)
3 number of sections
4EA196CA time date stamp Fri Oct 21 17:59:06 2011
166 file pointer to symbol table
9 number of symbols
0 size of optional header
0 characteristics
[...]
SECTION HEADER #3
.text name
0 physical address
0 virtual address
B size of raw data
15B file pointer to raw data (0000015B to 00000165)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60500020 flags
Code
16 byte align
Execute Read
RAW DATA #3
00000000: 55 8B EC 8B 45 08 83 C0 01 5D C3 U.ì.E..À.]Ã
[...]
COFF SYMBOL TABLE
000 00837809 ABS notype Static | @comp.id
[...]
008 00000000 SECT3 notype () External | _func
Bon j’ai coupé tous les informations qui ne nous concerne pas. On a donc un file header avec 2 ou 3 infos, puis des sections, regardons la section #3: c’est cette section qui contient le code compilé de notre fonction. Puis en fin de fichier on a la table des symboles qui contiens le nom de notre fonction.
Bon alors on ce lance dans la création du programme:
#include <windows.h>
#include <stdio.h>
#pragma pack(push, 1)
struct filehdr { //Thanks to tcc
unsigned short f_magic;
unsigned short f_nscns;
long f_timdat;
long f_symptr;
long f_nsyms;
unsigned short f_opthdr;
unsigned short f_flags;
};
typedef struct _SymbolTable {
unsigned char name[8] ;
unsigned int value ;
unsigned short sectionNumber ;
unsigned short type ;
unsigned char storageclass ;
unsigned char NumberOfAuxSymbol ;
} SymbolTable ;
#pragma pack(pop)
int main(int argc, TCHAR* argv[])
{
FILE *file = fopen( "out.obj", "wb" );
filehdr header = {
0x014c, //x86
1, // number of section
0, // time date stamp
0x47, // file pointer to symbol table
1, // number of symbols
0, // size of optional header
0x0, // characteristics
};
fwrite( &header, 1, sizeof(header), file );
//Shell code
BYTE rawdata[] = { 0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0x83 ,0xC0 ,0x01 ,0x5D ,0xC3 } ;
IMAGE_SECTION_HEADER archive_header = {
".text",
0,
0,
sizeof(rawdata),
sizeof(header)+sizeof(archive_header),
0,
0,
0,
0,
0x60500020,
};
fwrite( &archive_header, 1, sizeof(archive_header), file );
fwrite( &rawdata, 1, sizeof(rawdata), file );
SymbolTable symtab = {
"_func", //short name
0,
1,
0x20, //function 0x0 not function
0x2,
0x0 };
fwrite( &symtab, 1, sizeof(symtab), file );
char c = 0;
for (int i=0;i<10; i++)
fwrite( &c, 1, 1, file );
fclose(file);
return 0;
}
Bon on peut tester avec utilitaire dumpbin.exe, mais on peut même compiler avec un autre code source: on creer un fichier main.c
int main(int argc, char** argv)
{
return func(atoi(argv[1]));
}
Puis on compile avec la commande cl.exe main.c out.obj, on test
main.exe 41
echo %ERRORLEVEL%
42
Bon la encore c’est pas la démo de l’année mais sa marche !