The other Code Cave


This is a support article for my (soon-to-be) new About page. It explains one meaning of a “Code Cave”. It also shows you how to use a Code Cave that was left in Notepad to hack in some new functionality.

You can (soon EDIT: OK, I guess I lied -b) see the about page for an even better description of a Code Cave. I’ll summarize here by saying that taking advantage of a code cave is just one method commonly used by gamers to get past anti-cheat/PunkBuster measures in multiplayer games like Quake I-IV, Return to Castle Wolfenstein, Call of Duty and others.

This site is not going to get into hacking very much. I’ll probably just explain a few website vulnerabilities, just because they are cool and the fact that other sites published them has taught me how to write good code – and that IS a subject covered by this site. So, here is the OTHER meaning of a Code Cave and why I get some stray hits from people searching Google for hacking tools!

NOTE: if you do look for original versions of this article, be aware that:

  • it is full of MS html spam
  • the files it links to are infected with a virus
  • I also censored the language so I could keep my General Audience/Safe for kids rating on my site.
  • the files some how download from the link even though you hit cancel. I wouldn’t have believed it if I hadn’t seen it myself. I am CERTAIN I hit cancel because I didn’t get a save as dialog even though the infected file appeared in my internet cache.

That’s just a BIT bothersome. So, you might want to avoid it all together.

How to extend Notepad’s functionality by adding code to caves – by defiler.

  (AKA – How to hack notepad into saving encrypted text files.)

  Published by Tsehp.September 2000.

  Cleaned up by by Brian Layman 12/MAR/2006.

You may ask yourself “Why Notepad again?”. Well, the reason is that Notepad is a good and small target.

Tools I used this time:

  1. SoftIce v4.05 (SIce)

  2. Hiew 6.16

Some words:
This essay is based on an old idea I had a year ago. I realized this idea, but I didn’t know anything of the PE-format at all, so I just overwrote some other code. This time I will be using caves, no code gets overwritten. 😉

The idea:
We will make Notepad to ‘encrypt’ its buffer before it’ll be saved to disc.

The essay:

First, we have to find a code cave, some space between 2 sections.

This can be done very fast by loading Notepad.exe into Hiew 😉

Switch mode from “Text” to “Decode” by pressing F4 then F3 (I assume you know how to use Hiew.  So I won’t explain any further).

Press F8 to show up the PE-Header, then F6 for the Object-Table. You’ll see all the sections listed, beginning with the code-, then the data-section. The relevant properties of the objects are “PhysSize” and “Offset”; they’ll show the size of unused bytes between the sections (called ‘caves’).

By looking at the ObjectTable you see:

PhysSize of .text: 4000
Offset of .text:     1000
Adding them together: 5000

This value is the offset of the end of the .text section

Now have a look at the Offset of the .data section (PhysSize ain’t important):

Offset of .data:     5000

You see? Both offsets match… Hmmm but maybe there are some unused bytes anyway?

Let’s see… Select the first section (.text) and press enter.
We landed at 401000, it’s the beginning of the code (.text) section (NOT the EnytrPoint!!)
As you may remember, its physical size was 4000. Add this value to 401000 and we have the end of the .text section (405000). Jump to this address by pressing F5, then enter “.405000” (don’t forget the dot).

So we are directly “between” the .text and the .data section. If you scroll up a bit, you’ll see rather lot of 0-bytes (I guess they’re unused, as the characteristics for this section is 60000020).

You scroll up until you see the last non-crap instruction of the .text section. You should be at 404E96 (there’s a jmp GetFileTitleA), 404E9C may be the first byte we could use. Now press Ctrl-D to get into our beloved ring0 debugger, just to calculate the number of bytes we can use – type “? 405000 – 404E9C”.

SoftIce gives us: 164h = 356, a lot of bytes, at least for our purpose.

OK, we got almost all necessary stuff to start adding some code:
404E9C, the RVA of the unused bytes, where we’ll insert our code and 356 bytes to use.  Just one thing missing: The address of the routine, that reads in Notepad’s textbuffer.

After reading in the textbuffer we have to jump immediately to our routine to encrypt it. And this is how we can get it: Create an empty textfile, run Notepad.exe, open the empty file and write some text. Press Ctrl-D and type “bpx CreateFileA”, I guess it uses this API to save the file. Get back to Windows again, select File/Save.

We are inside Kernel32!CreateFileA, after pressing F11 (g @ss:esp) we are back in Notepad!.text+21E5:

0167:004031df  ff15c0634000        call      [KERNEL32!CreateFileA]
0167:004031e5  eb2a                jmp       00403211     ;here we are!
0167:004031e7  6a02                push      02
           ...           ...       .... I left out some code here, cause we directly jump to 403211, we'll trace some code there...

0167:0040320f  33f6                xor       esi,esi
0167:00403211  a340564000          mov       [00405640],eax ;save handle
0167:00403216  83f8ff              cmp       eax,-01     ;error ?
0167:00403219  7524                jnz       0040323f     ;no? then go on at 40323F
0167:0040321b  85ff                test      edi,edi
0167:0040321d  7419                jz        00403238
           ...           ...         ...

We don’t need the errorhandler…

Here we get, if no error occured…

0167:0040323f  33ff                xor       edi,edi
0167:00403241  a104504000          mov       eax,[00405004]
0167:00403246  57                  push      edi
0167:00403247  57                  push      edi
0167:00403248  68c8000000          push      000000c8
0167:0040324d  50                  push      eax
0167:0040324e  ff15d8644000        call      [USER32!SendMessageA]

hmmm.. sendmessage, maybe it uses WM_GETTEXT ?

Let’s look up SendMessageA parametres in win32.hlp:

LRESULT SendMessage(

    HWND hWnd,    // handle of destination window
    UINT Msg,    // message to send
    WPARAM wParam,    // first message parameter
    LPARAM lParam     // second message parameter

We need UINT Msg, it is the 3rd parametre pushed onto stack (remember LIFO!).
In our case it is 000000C8, so we go visiting SIce and typing “wmsg C8”.
SIce gives us: 00C8  EM_FMTLINES

Nope, we were wrong. Ok, we go on tracing…

0167:00403254  57                  push      edi
0167:00403255  8945f8              mov       [ebp-08],eax
0167:00403258  57                  push      edi
0167:00403259  a104504000          mov       eax,[00405004]
0167:0040325e  6a0e                push      0e
0167:00403260  50                  push      eax
0167:00403261  ff15d8644000        call      [USER32!SendMessageA]

Another SendMessageA, this time with UINT Msg == 0E. Back in SIce we type
“wmsg 0e” == WM_GETTEXTLENGTH, this one is good! …but we don’t want it 😛
go on..

0167:00403267  8d5801              lea       ebx,[eax+01]
0167:0040326a  6a42                push      42
0167:0040326c  53                  push      ebx
0167:0040326d  8945fc              mov       [ebp-04],eax
0167:00403270  a144564000          mov       eax,[00405644]
0167:00403275  50                  push      eax
0167:00403276  ff15a4634000        call      [KERNEL32!LocalReAlloc]

hmmm… LocalReAlloc, look at the API reference:

“The LocalReAlloc function changes the size or the attributes of
a specified local memory object. The size can increase or decrease.”

Ahhhhh! It enlarges/decreases memory after getting the size of our textbuffer =)

0167:0040327c  a344564000          mov       [00405644],eax ;save handle
0167:00403281  3bc7                cmp       eax,edi     ;some testing for errors
0167:00403283  7520                jnz       004032a5     ;if no error -> 4032A5
    ....        ...    ...    ... blahblah

0167:004032a5  a144564000          mov       eax,[00405644]
0167:004032aa  50                  push      eax
0167:004032ab  ff15a0634000        call      [KERNEL32!LocalLock]

ahhh, LocalLock, I know what it does:

“The LocalLock function locks a local memory object and
returns a pointer to the first byte of the object’s memory block.”

We do slowly but at least we DO come closer to our routine… =)

0167:004032b1  50                  push      eax
0167:004032b2  8bf8                mov       edi,eax
0167:004032b4  53                  push      ebx
0167:004032b5  a104504000          mov       eax,[00405004]
0167:004032ba  6a0d                push      0d
0167:004032bc  50                  push      eax
0167:004032bd  ff15d8644000        call      [USER32!SendMessageA]

Again a sendmessage. Get into SIce, type “wmsg 0d”:


Great! Look it up in the API reference:

“An application sends a WM_GETTEXT message to copy the text
that corresponds to a window into a buffer provided by the caller.”

wParam = (WPARAM) cchTextMax;   // number of characters to copy
lParam = (LPARAM) lpszText;     // address of buffer for text

Return Values: The return value is the number of characters copied.

Hmmm, we need the length AND a pointer to a buffer as return values…

Have a look at the API reference (once again ;), then at address 4032b1.

Eax is the pointer to the buffer, at line 4032b2 it is copied to edi.
And it won’t be changed as I figured out! After SendMessageA we have
edi==pointer to buffer and eax==return value of SendMessageA==length of buffer.

Followed by some code, that will write this buffer to a file:

0167:004032c3  ff75fc              push      dword ptr [ebp-04]
0167:004032c6  57                  push      edi
0167:004032c7  ff3540564000        push      dword ptr [00405640]
0167:004032cd  ff1564634000        call      [KERNEL32!_hwrite]
0167:004032d3  3b45fc              cmp       eax,[ebp-04]
0167:004032d6  7442                jz        0040331a

Great. Here we got to insert a jump to our code somewhere. I think we’ll take the line at 4032C7, gonna insert the jump to our code (remember, our location was 404E9C).

Of course, we got to restore the overwritten bytes inside our code again.
Our jump needs 5 bytes, so the “push dword ptr [00405640]” instruction has to be restored again.

Press F5 (GOTO) then type “.4032C7”, then F3 “EDIT” and finally F2 to switch to asm.

Enter “jmp 4E9C” press return, then “nop” and return, then escape.

Then press F9 and our jump is done. Now we’ll code the “encryption”.

We are at 4032CD now, that’s where we got to jump back to.
Jump to the cave, where we’ll add this code by pressing F5 and typing “.404E9C”.

Now remember, edi was a pointer to the textbuffer and eax the size of the buffer in bytes.

So we’ll make an easy ‘encryption’, you may write your own, mine is rather cheap, a simple XOR plus a ROL instruction ;).

pushad             ;save registers
xchg eax, ecx         ;ecx=size of buffer
xor b,[edi],64         ;remember: edi is a pointer to our buffer,
rol b,[edi],cl         ;some simple encryption
nop             ;some nops for further changes
inc edi             ;increment pointer to buffer (next char)
loop simplecrypt         ;loop until ecx=0 -> end of buffer
popad             ;restore registers
push d,[00405640]        ;remember? we have to restore the overwritten
                    ;push instruction from 4032C7 !!
jmp 32CD         ;we got to jump back to the code at 4032CD

OK, we are still at 404E9C. Press F3, then F2 and enter the code above.
The label “simplecrypt” is located at 404E9E, so you won’t type “loop simplecrypt”, you’ll type “loop 4E9C”. Finally press F9 and we have finished the encryption-code.

(The remainder of this article has been removed as it contained no content and only referenced virus infected files (that download in the original doc EVEN if you hit cancel.))

Add a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.