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. ;)
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 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
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 here...
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
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,[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 :P
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 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,[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
resotored
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
lamecrypt:
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
nop
nop
nop
nop
nop
nop
nop
inc edi
;increment pointer to buffer (next char)
loop lamecrypt
;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 "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.
Included
are my modified version and my orginial version
of notepad.
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 ;)
Group/chan
greets:
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:
defiler@eliteFravias.de