Visual Studio CppUnit Wizard Template

17 avril 2012

Extraire le zip dans le repertoire C:\Program Files\Microsoft Visual Studio 9.0\VC\VCWizards
CppUnitWizard.zip
Dans le repertoire C:\Program Files\Microsoft Visual Studio 9.0\VC\VCAddClass
Creer un fichier CppUnitTest.vsz avec le contenu :

VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.9.0
Param= »WIZARD_NAME = CppUnit »
Param= »WIZARD_UI = TRUE »

Après dans un project C++ clique droit sur le project > Add > Class… > Sélectionner Visual C++ puis CppUnitTest

Linux convertion WMA en MP3

17 avril 2012

J’ai une petite liste de fichier MP3 que j’essaie d’assainir des méchants fichier WMA. Et voila j’ai touvé la solution pour convertir toutes les fichiers WMA de ma bibliothèque, grace à FFMPEG:

find . -name *.wma -execdir ffmpeg -i {} -ab 128k -threads 0 -map_meta_data 0:0 {}.mp3 \;

Placé vous à la racine de votre répertoire racine, et la commande va scanner tous les wma les convertir avec un encodage en 128k, elle permet aussi de conserver les tags des fichiers wma. L’option thread 0 permet d’utiliser tous les processeurs de votre machine pour accélérer le traitement.

C++ surcharge de l’opérateur de comparaison

24 novembre 2011

Le langage C++ permet de surchargé les opérateurs ce qui permet de faire des opérations comme la comparaison entre des objets.

De plus comme la STL est bien implémenté il est possible aussi d’utilisé dans des conteneurs l’appel à la surcharge de l’opérateur de comparaison.

Comme d’habitude un exemple vaut mieux qu’un long discourt:

#include <vector>
#include <iostream>

using namespace std ;

class A
{
 int _a ;
public:
 A( int a ) : _a(a) {}
 virtual bool operator==(const A& p) const
 {
 return ( _a == p._a );
 }
};

class B : public A
{
 float _b ;
public:
 B( int a, float b ) : A(a), _b(b) {}
 virtual bool operator==(const A& p) const
 {
 if ( A::operator ==(p) != true )
 return false ;
 const B& pp = dynamic_cast<const B&>(p);
 return ( _b == pp._b );
 }
};

template<class T>
void print( const char* text, const T& p1, const T& p2 )
{
 cout << text ;
 try
 {
 if ( p1 == p2 )
 cout << " => true" ;
 else
 cout << " => false" ;
 } catch (...)
 {
 cout << " => Exception" ;
 }
 cout << endl;
}

int main()
{
 B b1( 1, 1.1f );
 B b2( 1, 1.1f );
 print( "b1( 1, 1.1 ) == b2( 1, 1.1 )", b1, b2 );
 B b3( 1, 1.2f );
 print( "b1( 1, 1.1 ) == b3( 1, 1.2 )", b1, b3);
 print( "b3( 1, 1.2 ) == b3( 1, 1.1 )", b3, b1);
 A a1( 1 );
 print<A>( "a1( 1 ) == b1( 1, 1.1 )", a1, b1 );
 print<A>( "b1( 1, 1.1 ) == a1( 1 )", b1, a1 );

 vector<B> vb1;
 vb1.push_back( b1 );
 vb1.push_back( b2 );
 vb1.push_back( b3 );

 vector<B> vb2;
 vb2.push_back( b1 );
 vb2.push_back( b2 );
 vb2.push_back( b3 );

 print("vb1 == vb2", vb1, vb2 );
 print("vb2 == vb1", vb2, vb1 );

 vb1[0] = b3 ;
 print("vb1 == vb2", vb1, vb2 );
}

Sortie console :

b1( 1, 1.1 ) == b2( 1, 1.1 ) => true
b1( 1, 1.1 ) == b3( 1, 1.2 ) => false
b3( 1, 1.2 ) == b3( 1, 1.1 ) => false
a1( 1 ) == b1( 1, 1.1 ) => true
b1( 1, 1.1 ) == a1( 1 ) => Exception
vb1 == vb2 => true
vb2 == vb1 => true
vb1 == vb2 => false

C++ et Functor

17 novembre 2011

Si vous etes comme moi vous faite joujou avec tout un tas de nouveau langage. Comme par exemple en C# j’apprécie l’utilisation des delegates, bien que je trouve leur appel ou leur déclaration un peu lourde. Mais voila tous les jours on est appeler a touché le langage de Bjarn. Est je viens de découvrir des appels sympathiques avec les STL.

Ce code permet d’effectuer un filtre sur une liste d’objet stocké dans un vecteur, ce filtre peut etre surchargé pour pouvoir le surchargé quand on le souhaite.

J’ai écrit un code similaire pour de sérialisation, ou des objets était sérialisé de manière récursive. Le rajout d’un filtre de ce type ma permit de sérialisé que certain type d’objet, en passant en parrametre le filtre dans ma fonction de sérialisation.

#include <vector>
#include <iostream>
#include <functional>

class Module
{
 int _i ;
public:
 Module(int i) : _i(i) {}
 int get() const { return _i; }
};

struct Filter : public std::unary_function<Module*,bool>
{
 virtual bool operator()(Module* p) = 0 ;
};

struct MyFilter : public Filter
{
 int _limit ;
 MyFilter(int limit) : _limit(limit) {}
 virtual bool operator()(Module* p) { return p->get() > _limit ; }
};

void display( const std::vector<Module*>& vec, Filter* filter)
{
 std::vector<Module*>::const_iterator it ;
 for (it=vec.begin();it!=vec.end();++it)
 {
 if ( (*filter)(*it) )
 std::cout << (*it)->get() << std::endl ;
 }
}

int main()
{
 std::vector<Module*> v ;
 v.push_back( new Module(1) );
 v.push_back( new Module(5) );
 v.push_back( new Module(10) );
 v.push_back( new Module(15) );
 v.push_back( new Module(20) );

 MyFilter f(10);

 display( v, &f );
}

ps : ceci est un exemple en STL un filtre sur le suppérieur est beaucoup plus simple :

#include <algorithm>
std::vector<int> vec(10);
std::remove_if( vec.begin(), vec.end(), std::bind2nd(std::less<int>(), 10) );

 

Génération de fichier obj (COFF)

21 octobre 2011

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 !

Comment générer un fichier executable

17 octobre 2011


La finalité d’un compilateur est de fournir un fichier binaire. Je me suis donc penché sur le cas Windows. Les fichiers « exe » de Microsoft Windows sont nommé PortableExecutable, ou PE. Après une entête il permet de stoker des données et du code binaire exécutable dans un seul fichier.

Nous allons réutilisé le code de l’article du shell-code sous Windows, pour genérer notre fichier. Rien est bien compiler mais il faut remplir des stucts à la main.

#include <windows.h>
#include <stdio.h>

void writeEmpty( FILE *file, int size )
{
	char empty = '\0' ;
	for (int i=0;i<size;i++)
		fwrite( &empty, 1, 1, file );
}

int main()
{
	int pos = 0;
	FILE *file = fopen( "out.exe", "wb" );
	IMAGE_DOS_HEADER image_dos_header;
	IMAGE_NT_HEADERS image_nt_headers;
	IMAGE_OPTIONAL_HEADER& image_optional_header  = image_nt_headers.OptionalHeader ;
	IMAGE_SECTION_HEADER image_section_header;
	char shellcode[] = "\x55\x89\xE5\x6A\x64\x68\xB8\x01\x00\x00\xBB\xA7\x7A\x83\x7C\xFF\xD3\x89\xEC\x5D\xC3";
	char dos_str[] = "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21\x54\x68\x69\x73\x20\x70\x72\x30\x67\x72\x61\x6D\x20\x63\x61\x6E\x6E\x30\x74\x20\x62\x65\x20\x72\x75\x6E\x20\x69\x6E\x20\x44\x4F\x53\x20\x6D\x30\x64\x65\x2E\x0D\x0A\x24\x00\x00\x00\x00\x00\x00\x00\x00" ;
	memset( &image_dos_header, 0, sizeof(image_dos_header) );
	image_dos_header.e_magic = IMAGE_DOS_SIGNATURE ; //0x5A4D ;
	image_dos_header.e_cblp = 0x0090 ;
	image_dos_header.e_cp = 3 ;
	image_dos_header.e_cparhdr = 4 ;
	image_dos_header.e_maxalloc = 0xFFFF ;
	image_dos_header.e_sp = 0x00B8 ;
	image_dos_header.e_lfarlc = 0x0040 ;
	image_dos_header.e_lfanew = sizeof(image_dos_header)+sizeof(dos_str)-1;//e_lfanew : Ce champ pointe vers l'entête PE.
	fwrite( &image_dos_header, 1, sizeof(image_dos_header), file );
	pos += sizeof(image_dos_header);
	fwrite( dos_str, 1, sizeof(dos_str)-1, file );
	pos += sizeof(dos_str)-1;
	memset( &image_nt_headers, 0, sizeof(image_nt_headers) );
	image_nt_headers.Signature = IMAGE_NT_SIGNATURE ; //0x00004550  // PE00
	image_nt_headers.FileHeader.Machine = 0x014c ; //386
	image_nt_headers.FileHeader.NumberOfSections = 1 ;
	image_nt_headers.FileHeader.SizeOfOptionalHeader = 0x00E0 ;
	image_nt_headers.FileHeader.Characteristics = 0x030F ;
	image_optional_header.Magic = 0x010B ;
	image_optional_header.MajorLinkerVersion = 0x06 ;
	image_optional_header.MinorLinkerVersion = 0x00 ;
	image_optional_header.AddressOfEntryPoint = 0x00001000 ;
	image_optional_header.BaseOfCode = 0x1000 ;
	image_optional_header.SizeOfImage = 0x2000 ;
	image_optional_header.ImageBase = 0x00400000 ;
	image_optional_header.SectionAlignment = 0x00001000 ;
	image_optional_header.FileAlignment = 0x00000200 ;
	image_optional_header.MajorOperatingSystemVersion = 0x0004 ;
	image_optional_header.MinorOperatingSystemVersion = 0x0000 ;
	image_optional_header.MajorSubsystemVersion = 0x0004 ;
	image_optional_header.SizeOfHeaders = 0x00000200 ;
	image_optional_header.Subsystem = 0x0002 ;
	image_optional_header.SizeOfStackReserve = 0x00100000 ;
	image_optional_header.SizeOfStackCommit = 0x00001000 ;
	image_optional_header.SizeOfHeapReserve = 0x00100000 ;
	image_optional_header.SizeOfHeapCommit = 0x00001000 ;
	image_optional_header.NumberOfRvaAndSizes = 0x00000010 ;
	fwrite( &image_nt_headers, 1, sizeof(image_nt_headers), file );
	pos += sizeof(image_nt_headers);
	memset( &image_section_header, 0, sizeof(image_section_header) );
	strcpy( (char*)(image_section_header.Name), ".idata" );
	image_section_header.Misc.VirtualSize = sizeof(shellcode) - 1 ;
	image_section_header.VirtualAddress = 0x1000 ;
	image_section_header.SizeOfRawData = 0x200 ;
	image_section_header.PointerToRawData = 0x200 ;
	DWORD d1 = (DWORD)&image_section_header ;
	DWORD d2 = (DWORD)&(image_section_header.PointerToRawData) ;
	image_section_header.PointerToRawData = 0x200 ;
	image_section_header.Characteristics = 0x60000020 ;
	fwrite( &image_section_header, 1, sizeof(image_section_header), file );
	pos += sizeof(image_section_header);
	writeEmpty( file, 0x200 - pos );
	fwrite( shellcode, 1, sizeof(shellcode)-1, file );
	writeEmpty( file, 0x200-sizeof(shellcode)+1 );
	fclose( file );
}

source TinyPE, PE File Format

De l’utilisation du const en Programmation Objet

10 juin 2011

Une chose est sur le mot clé const est bien souvent négligé. Alors que ce mot clé existe depuis le C, mais la programmation Objet lui confère de nouvelles possibilitées. Donc je partirai du principe que vous maitrisé l’utilisation du const en C. Juste ce petit rappel:

int function1(int&amp; i) // ok
{
    return ++i ; //On modifie i et on a le droit
}
int function2(const int i) // ok
{
    int a = i ;
    //return ++i ; error C3892: 'i' : you cannot assign to a variable that is const
    return a+1 ;
}
int function3(const int&amp; i)
{
    int a = i ;
    //return ++i ; error C3892: 'i' : you cannot assign to a variable that is const
    return a+1;
}

Rentrons maintenant dans le vif du sujet, l’utilisation du const en PO. Pour présenté, je vais vous parler des accesseurs.

class Usage
{
     int m;
public:
    const int& get() const { return this->m; }
    void set(const int& v) { this->m = v ; }
};

Pour accéder au membre m de la classe il est préférable de ne pas la déclaré en public mais d’ajouter deux fonctions membres get et set. Ici pour simplifié l’exemple le type du membre m est de type int, l’utilisation de passage par référence n’est donc pas là pour la réduction d’utilisation de la mémoire mais comme exemple.
En effet, la fonction membre m déclaré comme const, informe que l’appel de cette fonction ne pourra modifier aucun de ses membres.

Utilisation d’un membre const

Une autre possibilité est l’utilisation d’un membre const, celui-ci devra est obligatoirement affecté dès le début du constructeur, comme-ci:

class Usage
{
     const int mc;
public:
    Usage(const int& v) : mc(v) {}
    Usage(const int& v) { mc = v; } //ERREUR
    void set(const int& v) { mc = v; } //ERREUR
};

Mais à quoi donc cela peut bien servir? Voici un petit exemple :

#include <string>
class Usage
{
    const std::string mObjectName ;
public:
    Usage(const std::string& name) : mObjectName(name) {}
};

Le nom de l’objet est affecté dès la construction de celui-ci et ne sera plus jamais modifiable jusqu’à la fin de sa vie.

Const et l’héritage

Il est tout à faire possible et même conseillé d’hérité des fonctions const :

class UsageBase
{
    virtual void override() const = 0 ;
};
class Usage : public UsageBase
{
    virtual void override() const { //fait des choses mais sans affecté les membres }
};

Const et la STL

Il faut savoir une petit chose sur l’utilisation des itérateurs et le mot clé const, il existe son homologue const_iterator, les STL sont quand même bien faites!

class Usage
{
    std::vector<int> ml;
    bool find(const int& v) const
    {
        std::vector<int>::const_iterator it = ml.begin();
        for( ; it != ml.end(); it++ )
            if ( v == *it )
                return true;
        return false ;
    }
};

Maintenant que vous savez tous sur les const, n’hésiter plus à l’employer à toutes les sauces !

Détection de visage sous facebook

31 mars 2011

Après avoir appris que des personnes on réussit a récupéré 100 million de profile publique, je me suis intéressé au plus connu des sites sociaux.

En effet, c’est fichier contiennent une liste de nom récupéré sur facebook avec leurs identifiants. De la le pas est facile, si il est possible de récupérer les informations des comptes il est peut être possible de récupéré la photo du profil est d’appliquer une détection de visage. Cela pourrai être très intéressant la plus grand base de données mondial de visage disponible gratuitement, mais d’un autre coté cela est surtout fait pour montrer le danger que peut soulevé les sites sociaux.

La première étape est de récupérer l’identifiant correspondant à un compte généralement il suffit de regarder dans l’url correspondant à un compte. Par exemple :

id=68310606562

Maintenant l’url magique pour récupérer la photo :

wget https://graph.facebook.com/68310606562/picture?type=large -0 profil.jpg
display profil.jpg

Après avoir récupéré la photo, il nous faut un traitement d’image pour détecter un visage pour la photo, pour cela on va utilisé la bibliothèque de traitement d’image OpenCV. Cette bibliothèque possède une routine dite détection d’objet Haar. Voila une petit programme C++ permettant de la mettre en œuvre.

#include "cv.h"
#include "highgui.h"

CvHaarClassifierCascade* load_object_detector( const char* cascade_path )
{
 return (CvHaarClassifierCascade*)cvLoad( cascade_path );
}

bool detect_and_draw_objects( IplImage* image,
 CvHaarClassifierCascade* cascade,
 int do_pyramids )
{
 IplImage* small_image = image;
 CvMemStorage* storage = cvCreateMemStorage(0);
 CvSeq* faces;
 int i, scale = 1;

 /* if the flag is specified, down-scale the input image to get a
 performance boost w/o loosing quality (perhaps) */
 if( do_pyramids )
 {
 small_image = cvCreateImage( cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3 );
 cvPyrDown( image, small_image, CV_GAUSSIAN_5x5 );
 scale = 2;
 }

 /* use the fastest variant */
 faces = cvHaarDetectObjects( small_image, cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING );

 if ( faces->total != 1 )
 return false ;

 /* draw all the rectangles */
 for( i = 0; i < faces->total; i++ )
 {
 /* extract the rectanlges only */
 CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i );
 cvRectangle( image, cvPoint(face_rect.x*scale,face_rect.y*scale),
 cvPoint((face_rect.x+face_rect.width)*scale,
 (face_rect.y+face_rect.height)*scale),
 CV_RGB(255,0,0), 1 );
 }

 if( small_image != image )
 cvReleaseImage( &small_image );
 cvReleaseMemStorage( &storage );
 return true ;
}

int main( int argc, char** argv )
{
 IplImage* image;
 if( argc==4 && (image = cvLoadImage( argv[1], 1 )) != 0 )
 {
 CvHaarClassifierCascade* cascade = load_object_detector(argv[2]);
 if ( detect_and_draw_objects( image, cascade, 1 ) )
 cvSaveImage( argv[3], image );
 cvReleaseHaarClassifierCascade( &cascade );
 cvReleaseImage( &image );
 }
 return 0;
}

Bon on compile le tout, on lance le programme avec une base xml contenant les informations pour une bonne détection de visage de face. Et on obtient de bon résultat sur quelques photos. Pour la suite il est possible, bien que le traitement utilisé ne si prete peu, de récupérer les informations spécifique du visage pour faire une recherche dans une base depuis une image source. Comme dans les films il serait donc possible de retrouve une liste de profile correspondant à une image source. Bien que la résolution des images des profiles est assez bases, et que l’on a pas tout le temps la tête bien centré, ou plusieurs visages, voir carrément une photo qui ne correspond pas à la personne. D’ailleurs je ne peux que vous conseiller de ne pas mettre une photo de vous sur votre profil.

ShellCode sous windows

8 mars 2011

On a vue comment faire un shellcode sour linux, mais maintenant passons sous windows. On va ecrit en premier le code que l’on voudra exécuter, ici on choisi la fonction Beep qui émette un son.

#include <windows.h>
void main()
{
 Beep( 440, 100 );
}

Pour le compiler je vous conseille le petit compilateur TCC.

tcc code.c
code.exe

Pour décompiler on peut utiliser OllyDbg, et pour compiler de l’assembleur FASM est très puissant. Donc c’est pas très compliquer d’écrire la correspondance en assembleur.

format    PE console
include 'win32ax.inc' ;
start:
 push ebp
 mov ebp,esp
 push 100
 push 440
 mov ebx, 0x76fa38a9
 call ebx
 mov esp,ebp
 pop ebp
 ret
.end start

Bon mais c’est quoi ce 0x76fa38a9 ? Tout les programmes sont au moins liée avec Kernel32.dll, sa tombe bien la fonction Beep est dedans. Mais pour récupérer l’adresse il nous faut un petit programme :arwin.c

tcc arwin.c
arwin kernel32.dll Beep
arwin – win32 address resolution program – by steve hanna – v.01
Beep is located at 0x76fa38a9 in kernel32.dll

Maintenant que l’on a tout on compile l’assembleur et on edit le code soit dans OllyDbg, soit tout simplement dans un éditeur hexadécimal comme HxD. On récupère les bytes correspondant au code, pour écrire ce code :

#include <windows.h>
typedef void (*Func)(void);
int main()
{
	char shellcode[] = "\x55\x89\xE5\x6A\x64\x68\xB8\x01\x00\x00\xBB\xA9\x38\xFA\x76\xFF\xD3\x89\xEC\x5D\xC3";
	Func func = (Func)shellcode ;
	func();
}

[sources]

Shellcode sous linux

5 mars 2011

Bon si on arrive a générer du bytecode en Java cela doit bien être possible en code assembleur? C’est même presque plus simple, on appelle même cela un shellcode: un buffer qui contient le code compiler. Cet article est très inspiré du site http://howto.shell-storm.org où tout est très bien expliqué et en français même!

Pour bien appréhendé cet article il vous faut, un linux (ici Ubuntu 10.10), tournant sur un pc x86 32bit (pour un precesseur x64 il faudrai modifier les appels systèmes, pour un processeur ARM tout changer :) )

Donc étape 1, fabrication du shellcode :

xor %eax,%eax #met le registre EAX à zero
mov $29,%al #on met 29 dans al
#29 est l'appel système pour pause
int $0x80 #l'appel system

Donc ce petit bout d’assembleur permet de faire un appel système à la fonction pause. Le 29 est l’identifiant de la fonction pause en x86. Comme cette fonction ne possède pas d’argument cela simplifie l’appel.

On compile :

$ as -o pause.o pause.s

Maintenant on demander le code assembleur du fichier générer mais en plus on aurra la correspondance entre le code assembleur, et les code machine correspondant.

$ objdump -d pause.o

pause.o:     file format elf32-i386
Disassembly of section .text:
00000000 <.text>:
0:    31 c0                    xor    %eax,%eax
2:    b0 1d                    mov    $0x1d,%al
4:    cd 80                    int    $0×80

Donc on remarque que 31 correspond à l’opération xor, b0 pour mov… Donc le shell code est 31,c0,b0,1d… Maintenant que l’on a le shellcode il faudrait pourvoir l’exécuter depuis un programme C:

#include <stdio.h>
void main(void)
{
    char shellcode[] = "\x31\xc0\xb0\x1d\xcd\x80";
    (*(void(*)()) shellcode)();
}

Pour la compilation si on fait juste un appel à gcc sans argument on se retrouve avec une erreur de segmentation. En effet, gcc rajoute des instructions permetant de limité la casse, pour continuer il va falloir désactivé ces protections. On compile donc avec la commande:

$ gcc -fno-stack-protector -z execstack -o pausec pause_c.c
$ ./pausec

Et lors de l’exécution le terminal reste bloqué, bon par très exceptionnel comme démo, mais un joli hello world sera pour un autre jour.