How to extend notepad's functionality by adding code to caves - by defiler.
Published by Tsehp.September 2000.
You may ask yourself "Why the hell notepad again?".
Well, the reason is, that notepad is a good and small target.
Tools i used this time:
(x) SoftIce v4.05
(x) Hiew 6.16
Some lame 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. ;)
We will make notepad to 'encrypt' its buffer before it'll be saved to disc.
First, we have to find a 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 "how-to-rape-hiew").
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
by 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". Sice 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
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 here...
0167:0040320f 33f6 xor esi,esi
0167:00403211 a340564000 mov ,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,
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:
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
shit, 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,
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 :P
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,
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 ,eax ;save handle
0167:00403281 3bc7 cmp eax,edi ;some testing for errors
0167:00403283 7520 jnz 004032a5 ;if no error -> 4032A5
.... ... ... ...
0167:004032a5 a144564000 mov eax,
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 com 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,
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
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 
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 " instruction has to be
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 lame encryption
nop ;some nops for further changes
inc edi ;increment pointer to buffer (next char)
loop lamecrypt ;loop until ecx=0 -> end of buffer
popad ;restore registers
push d, ;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 "lamecrypt" is located at 404E9E, so you won't type "loop lamecrypt", you'll
type "loop 4E9C". Finally press F9 and we have finished the encryption-code.
We have finished now, at least part 1, i need to learn for a maths test now,
maybe i'll update this essay tomorrow.
Greetings fly out to:
no specific order.
ultraschall, cardenal mendoza, kaparo, flwright, ratso, haldir, lightdruid, ganjaman,
telcofix, whataduck, tornado, hutch, masta, notty, knotty, kwazy webbit, secret, iczelion,
bisoux, MisterE, mr nop, neural noise, lazarus, peegee, random, daze, the anti xryst,
acid burn, azzyrian, decline, blind angel, keyboard junky, reverend x, DnNuke, Gizmo,
viny, volatility, alpine, promothee, sat0r, fli7e, targ0n, Ridlexx, novatrix, TomTom,
WarezPup, Weazel, visionz, kaai, MagicRaph, sepulcrum, MVD, sn00pee, sinn0r and all
who contribute to the reversing spirit ;)
all blizzard members, everyone in #win32asm, #cracking, #eliteFravias, #reversing4newbies,
#immortaldescendants, #digital.factory, #hellforge, and #learn2crack.
I would be pleased to get some feedback, catch me on irc or mail to: