The other Code Cave
Greetz!
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:
- SoftIce v4.05 (SIce)
- 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”:
000D WM_GETTEXT
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.”
WM_GETTEXT
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
simplecrypt:
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
nop
nop
nop
nop
nop
nop
nop
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.))