Shields Down! by Harlequin January 2001
|
|
|
Introduction |
You probably know of Steve Gibsons shields up website
(http://www.grc.com/) it is a pretty nice looking little site which
claims to test your Internet security. I don't know how
effective the site is and I propose no recommendations here. All it
does is a simple port scan on your computer using your IP address for
the computer to scan, it then tells you if you have any insecure open ports.
There is a problem here though, if you are connecting to the Internet
through a proxy server the IP address which is given to Mr Gibsons
site is not the one local to your machine rather it is that of your
proxy server. As I understand it (and I am no expert so please don't
quote me :) when you connect to a proxy server you are given an IP
address for communication between your machine and theirs. Now every
time you request something form the web your machine talks to theirs
tells them what it wants. Their machine then goes and gets it for you
and passes it back to your machine using your IP address. So Shields
up is not checking your machine rather, you are in fact checking that
of your proxy server.
Mr Gibson has a way around this though. A little program he calls
IP_Agent. All this program does is grab your local IP from your
machine encode it and send it along to the shields up site. This way
your machine is tested not your servers.
Now I don't know if there are any bells going of in your head here
but there certainly were in mine as soon as I saw this little
program. I considered, what if we were to be able to send along any
IP address we chose, would the shields up site not then scan that
computer and send the data back to us???
Steve Gibson tells us all his work is in Win32asm and he gives his work away for free. Why then is he so selfish with his ideas? I am only really a novice in Win32Asm but I love it and from that love I want to share what little I know so that we can encourage more folks to start using Win32asm and so keep it from being exterminated by these bigger, designed for dummies languages. Why then if Mr Gibson is so passionate about Win32Asm is he so protective of it, and he is protective believe me, as you will see in this essay, for a freeware program he has gone to extraordinary lengths to keep us out. Could be to stop just the sort of thing I have in mind perhaps but then he has used similar protection on all his other programs, such as OptOut. I thank him for this, it so far has been a very interesting journey.
So enough bull lets get on with it.................
The Essay |
Objectives:
Get a completely unpacked working version of IP_Agent.
Create an IP generator from the code.
Added appendix on Code Injection (See after Final notes)
#1
Layer1: The packer
Steve Gibson has used his normal packer on this little program, PECompact 1.2. This is pretty easily determined by looking at the section names, pec1 pec2..... (or you can use the excellent Getype utility.). Note though that the section names are not a reliable indicator, if and when I use packers I always edit the section headers back to normal ;-)
So lets remove PeCompact.
Open IP_Agent in procdump and you will see the program entry point
6964h and the base address of 400000h.
So load IP_Agent into softice using loader. Module load and softice
breaks, but there is no code! not to worry type:
bpx 00406964 to break on our entry point, Ctrl+D and we are at the
start of the unpacking routine.
Right here we can trace through the code F10'in etc etc etc but I
thought I would show you another option.
The first thing we can see PECompact doing is a pushad and a pushfd, if it does this then it is a pretty fair bet that one of the last things it will do is a popfd and popad. So lets save ourselves some hassle with a simple byte search for these instructions:
S 400000 l ffffff 61,9d
Notice I start the search in the programs memory no point in finding
out if every other program uses these instructions too.
As might be guessed at this early stage we get nothing found. Not to
worry, we can use some common sense to help us. Most programs due the
the segment alignment have a preferred loading address of 401000h so
assuming this PECompact is going to have to write to this address at
some time as it unpacks our program, so lets put a breakpoint on this address:
bpm 401000
Ctrl+D and we break almost immediately, unless you are running a 286
with Internet explorer installed, in this case I suggest you leave it
overnight ;-)
Use our up cursor key to reselect our search and try again. Bingo one
strike at 409466. Now type:
u 409466 to see what we have got. Looks pretty good, put a breakpoint
on the return, note that the push 401000 is our original entry point
and will vary from program to program.
Ctrl+D we break and then go through the usual:
a
jmp eip
ESC
Ctrl+D
and we have a madly looping program. Disable all breakpoints Ctrl+D
and fire up Procdump.
Select our program, right click and full dump, then kill the task.
Now we need to change the Entry point to our new one at 401000h minus
the base address so open it up in Procdumps PE editor and in the
entry point box enter 1000. Job done lets go play.
Note: the above method works for all versions of PECompact that I have come across.
Run our newly dumped program to make sure it works and we are greeted
with a nice little message box calling me evil. Me! evil?. Click ok
and the program shuts down. Lets go take a look in W32Dasm see what
we have got.
(If you have my previous W32Dasm patch installed you only need to
right click it and send to, if you have a w32dasm shortcut in your
send to folder :-)
OK so in w32dasm we see no string references and no imports, this is
not good. Back to Procdump, make sure you have the Rebuild import
table option selected then Rebuild PE.
Disassemble and we have our imports, still no strings though???? Open
the program in your hex editor and still no strings??
Perhaps he packed it twice with different packers, Load the program
and use the full dump of Procdump. Now we have strings. However when
we run it the messagebox is now full of jibberish!! This is nothing
to do with a packer, this is our Mr Gibson playing with us :-)
Put a breakpoint on MessageBoxA in softice and run our program. We
break, F11 ok to the message box and we are just after the call.
00401BA7h Check out the address for the message text at 402177h, its
full of junk.
No problem type:
bpm 402177 and Ctrl+D then run the program again. We break at 401B00
right in the middle of a nice little XOR routine. You have to ask why
all this is necessary in a freeware program. Still lets fix it! Load
it in W32Dasm and goto 401B00h.
Scroll up till you find the beginning of the function at 401AD8h
patch this instruction with a return 'C3', run it and we have our
message in readable format again. Now lets get rid of the thing,
check out the messagebox call at 00401BA7h, just above it we see the
jump if equal. Change this to EB (jump) and our messagebox is gone.
For the sake of interest it would seem with just a cursory glance
that the code which produces our little messagebox is a sort of CRC
check, whereby all the bytes of the file are added together. The
result must be zero. This must have involved calculating the sum of
all the bytes in the file taking the result away from zero then hex
editing in the last dword to be the resulting value. Some effort for
a free program eh?
Anyway that's about it, objective 1 achieved now we can get down to the fun stuff...
#2
An IP Generator.
Looking at our newly disassembled programs imports we see the following:
WSOCK32.gethostbyname
WSOCK32.gethostname
WSOCK32.WSACleanup
WSOCK32.WSAStartup
WSOCK32.WSAStartup
You don't have to be an Internet Guru to figure out these are what we are interested in. These functions are used to get the IP address from your computer. That's all very nice but we don't want our own IP address so we can pretty much ignore these functions themselves we need to take a look at the surrounding code though so we can identify where we want to inject our own IP address. There is no magic here a quick look at the deadlisting tells us that ebx indicates wether an IP address was successfully obtained, following the jumps also suggests that ebx contains the number of IP addresses which were found. Well we are only going to have one IP address at a time so we find our point of entry at:
:00401C6E 83FB01 cmp ebx, 00000001
:00401C71 750D jne 00401C80
:00401C73 FFB5A4FCFFFF push dword ptr [ebp+FFFFFCA4]
Looking into the following call we can see a very simple little routine which simply formats the IP string for output to the window.
:00401A3B 8B5508 mov edx, dword ptr [ebp+08]
The above line tells us quite a lot, the IP address is stored at
[ebp+08] but it must also be stored as a simple dword format. This
would make sense with each byte representing a part of the address.
Still not much of interest to us though, returning from the call and
following the jump we can see in the deadlisting as the 8 bytes
string 'xxxxxxxx' is loaded, then the base URL is loaded then there
is an internal call and finally the 'xxxxxxxx' are appended to the
URL. MMmmm doesn't take much to figure out that the little call is
what we are interested in.
So what does it do?? well it is some simple little encoding routine
which turns our dword IP address into an unrecognizable encoded
dword. How??? who the hell cares! all we are interested in is where
we inject our number and resolving any other memory references. So in
Softice Loader load the imports for WSOCK32.dll then place a
breakpoint in WSACleanup and run our little program. As soon as you
enter the code edit ebx to contain 1 and we are ready to trace down
to our call.
Inside you can watch as the function loads the IP address value I
comment the code below:
:00401A75 55 push ebp
:00401A76 8BEC mov ebp, esp
:00401A78 53 push ebx
:00401A79 56 push esi
:00401A7A 57 push edi
:00401A7B BB84254000 mov ebx, 00402584 --- memory address of some data
:00401A80 8B450C mov eax, dword ptr [ebp+0C] --- our IP dword
:00401A83 B904000000 mov ecx, 00000004 --- 4 bytes- put 4 in counter
:00401A88 D7 xlat --- lookup new value in data see below
:00401A89 C1C008 rol eax, 08
:00401A8C E2FA loop 00401A88 --- do em all
:00401A8E 8BF0 mov esi, eax --- save our new value in esi
:00401A90 8B4510 mov eax, dword ptr [ebp+10] --- number of IP addresses (ebx)
:00401A93 D7 xlat --- look it up too
:00401A94 C1E008 shl eax, 08
:00401A97 8B7D08 mov edi, dword ptr [ebp+08] --- our 'xxxxxxxx' string
:00401A9A BB01000000 mov ebx, 00000001
:00401A9F 33C9 xor ecx, ecx
:00401AA1 B608 mov dh, 08
and on it goes. All other references are local though so we need not
concern ourselves with any of it we have all we need.
So it is simplicity itself, to make a generator we only need place
our IP dword into eax at 00401A80h we need to put 01h into eax at
00401A90h and we need a copy of the lookup table.
XLAT works as follows:
XLAT/XLATB - Translate
Usage: XLAT translation-table
XLATB (masm 5.x)
Modifies flags: None
Replaces the byte in AL with byte from a user table addressed by
BX. The original value of AL is the index into the translate table.
The best way to discribe this is MOV AL,[BX+AL]
Simple enough we only need to grab the table. Use your RVA converter to find the file offset from the RVA 00402584h at the address it is pretty apparent what we need. Just select the whole block from your hex editor down to the '00' byte and copy it to the clipboard. Then you just paste it into your generator code as a string:
KeyTable db 'the data goes here',0
You will find there are three problem characters these are ' CR and LF. To get around these simply replace them with Their ascii values as follows:
KeyTable db 'First part of data',39,'next data',10,'some more data',0A,'and finally',0
Thats all there is to it, just cut and paste the whole routine into
your program, deliver the IP dword to it, move offset KeyTable into
ebx and we are done. When the function finishes the new IP address is
in EDI.
Converting the edit box text to a dword value requires a little work
I include my code for this commented below:
pushad
xor eax,eax
xor ebx,ebx
xor ecx,ecx --- save and clear everything
mov edi,offset IP_Address --- the edit box string in the format
--- xxx.xxx.xxx.xxx
dochar:
mov al,byte ptr[edi+ecx] --- 1st character in al
.IF al>39h || al<30h --- if it is not a valid number
.IF al==2Eh || al==00h --- see if it is a . or end of string
shl ebx,08h --- move last processed number left 1 byte
mov count,3 --- if part only has 2 digits 3rd will be zero
mov dl,1 --- our base multiplier
mov Temp,eax --- a copy of our digits
jmp convert --- turn them into hex value
.ENDIF
popad --- if it was not . or eos then it was invalid
mov edi,offset No_Name --- default string for edit box
RET --- and leave
.ENDIF --- if digit was a valid number
sub al,30h --- strip the ascii value
shl eax,8h --- store it by moving eax left 1 byte
inc ecx --- our character counter
jmp dochar --- get next digit
convert:
shr Temp,8h --- 1st digit was . or eos
mov eax,Temp --- copy our digits to eax
mul dl --- mulitply by base 10(1st pass 1,10 2nd,100 3rd)
add bl,al --- keep the total
xchg al,dl --- swap al-dl so we can mulitply
mul ten --- multiply our base by 10
xchg al,dl --- swap em back
dec count --- so we know when we have done 3 digits
jne convert --- keep going until
xor eax,eax --- bl now has our hex value of the decimal
inc ecx --- ip part (ie 123 now = 7Bh)
cmp ecx,length --- have we done all of string
jl dochar
mov eax,ebx --- put our IP dword in eax
mov ebx, offset KeyTable --- this is the translate table
mov ecx, 00000004h --- and away we go.
l00401A88:
xlat
rol eax, 08h
That's all there is to it. So little that I nearly didn't write this essay but what the hell someone might get something from it right??
In Conclusion |
I have not given to much detail on producing the actual generator because this really is a good opportunity for you to have a go. IP_Agent was written in W32Assembler and as such is very neat tidy and easy to read, you don't have to sort through reams of junk. This is an ideal target for a first keygen. My original aim was to inject my code into the program itself adding an edit box and calling the existing encoding routine. To be honest though I lost interest a little once I had unpacked the thing, it took about 30 minutes to write the keygen whereas it would have taken hours to inject the code. Perhaps you might do it?? should be fairly simple there is plenty of room, the only major problem to overcome is creating an edit box without a dialog box template. Mr Gibson only uses a window creating the button as another window so you would probably be best doing the same thing with an edit box :-)
Finally. Don't expect this Generator to work for long I am sure Mr Gibson will fix it pretty quickly :-)
See below for the code injection essay.
Final Notes |
Thanks go to: Anybody who takes the time to write an essay so that the rest of us can learn too.
Iczelion for his excellent tutorials, I have been
bumbling through this assembler for a while now and I thought it was
about time I read some tutorials. I only wish I had read them a long
time ago. That's engineers for you! All those kind enough to post my essays and tools.
|
Appendix |
Ah what the hell I have a couple of spare hours thought I might as well code inject the damm thing as well, just for the hell of it.
So briefly:
We need an edit box. I decide to place it down at the bottom over the 'by Gibson Research Corp' text.
First I hex edited the 'v1.0, copyright... blah blah' text to read
'Enter an IP Address:'
Next I needed to create the edit box so I patched in the following
code in w32dasms window and clicked 'Make Permenant' :-)
:00401EB0 60 pushad --- save all
:00401EB1 6A00 push 00000000 --- start CreateWindowExA pushes
:00401EB3 FF3534254000 push dword ptr [00402534] --- App inst as in button creation
:00401EB9 6801FF0000 push 0000FF01 --- An ID for my edit box
:00401EBE 8B1D38204000 mov ebx, dword ptr [00402038] --- this is the main window handle
:00401EC4 8B1B mov ebx, dword ptr [ebx] --- the same as button code except
:00401EC6 53 push ebx --- I calculated [esi+1C]
:00401EC7 6A0E push 0000000E --- EditBox Height
:00401EC9 6A78 push 0000007F --- EditBox width
:00401ECB 6A60 push 00000060 --- EditBox top
:00401ECD 6A0F push 0000000F --- EditBox Left
:00401ECF 90 nop --- These cause i screwed up the
:00401ED0 90 nop --- size first time and had to
:00401ED1 90 nop --- correct it
:00401ED2 6800000050 push 50000000 --- EditBox
:00401ED7 68A5264000 push 004026A5 --- window name see below
:00401EDC 68A0264000 push 004026A0 --- class name see below
:00401EE1 6A00 push 00000000 --- no style like me :-(
:00401EE3 E80EFEFFFF call 00401CF6 --- CreateWindowExA
:00401EE8 61 popad --- Reset all
:00401EE9 83C628 add esi, 00000028 --- instructions I will be
:00401EEC 4F dec edi --- overwritting see below
:00401EED 0F85F4FAFFFF jne 004019E7
:00401EF3 E938FBFFFF jmp 00401A30 --- return control
Right we need to fill a couple of data strings so at offset 1CA0h (4026A0h) I edit in 'EDIT' then at offset 1CA5h (4026A5h) I edit in 'xxx.xxx.xxx.xxx'. These are for the class name and window name respectively.
Ok now I need to get to my new code, I chose to jump after the CreateWindowExA for the button creation. I gave IP_Agent time to save the handle to the button first then jumped as follows:
:00401A13 6800000000 push 00000000
* Reference To: USER32.CreateWindowExA, Ord:0000h
|
:00401A18 E8D9020000 Call 00401CF6
:00401A1D 0BC0 or eax, eax
:00401A1F 7410 je 00401A31
:00401A21 8B5E24 mov ebx, dword ptr [esi+24]
:00401A24 0BDB or ebx, ebx
:00401A26 7402 je 00401A2A
:00401A28 8903 mov dword ptr [ebx], eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401A26(C)
|
:00401A2A E981040000 jmp 00401EB0 --- jump to my code
:00401A2F 90 nop --- Keep it tidy
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401EF3(U)
|
:00401A30 4F dec edi --- this is where i will return to
Ok thats it now I have my edit box all I need to do is go make it do something.
I did a search in the deadlisting for '000111' to find where the WM_COMMAND message is processed at 0040190Bh. Trace down a couple of lines to where we jump if the message was not the button at line 0040191Bh, looks like a good place to redirect :-) Ah but first I think I had better get myself a GetDlgItemTextA function. I decide to do this by adding it to the import table, as I won't be needing the old winsock functions any more I shall just jump over them like so:
:00401BBE 57 push edi
:00401BBF BB01000000 mov ebx, 00000001
:00401BC4 EB7E jmp 00401C44 --- jump over them all
:00401BC6 000000 BYTE 3 DUP(0)
Next hex edit WSOCK32.dll to USER32.dll, it's the last library isn't that fortunate :-). Whoa.. the brakes came on here for a second, there are no API names for the winsock functions, still that does not worry us in fact it makes it easier as we don't have to overwrite an existing one. Leave three 00 bytes after our dll name then edit in our function name 'GetDlgItemTextA' Leave two bytes at the end of the function name then insert 83370000h to point to our API function name (note this is the RVA of the function name not the offset) leave a complete 00000000 dword then enter 83730000h again for our second array. Make a note of the RVA's of these two arrays (MMMMmmmm problems) if you are using an RVA calculator like myself you would notice that you cannot calculate the VA's. Load the target into Procdump PE editor and you will see we have stepped out of section pec1 but not into section pec2?? We are in no mans land, a result of unpacking the file. Not a problem in Procdump change the Psize of pec1 to 27B6 to give us another 50 bytes in no mans land. Now this time you get a VA of 3796h for the first array and 379Eh for the second so lets go put them in the import table.
At offset 2664h enter 96370000h and at offset 2674h enter 9E370000h save the file and reload it into w32dasm and we no longer have any winsock functions instead we have our new DlgText function, amazing how simple this all is eh :-)
Ok now where were we? ah yes redirection......... before we redirect we need something to redirect to so I used w32dasms patcher to enter the following:
:00402800 3D01FF0000 cmp eax, 0000FF01 --- check if was our editbox
:00402805 0F8553F1FFFF jne 0040195E --- if not carry on as normal
:0040280B 60 pushad --- save all
:0040280C 6A20 push 00000020 --- set up GetDlgItemTextA
:0040280E 6800274000 push 00402700 --- Where our string will go
:00402813 6801FF0000 push 0000FF01 --- EditBox ID
:00402818 8B1D38204000 mov ebx, dword ptr [00402038]
:0040281E 8B1B mov ebx, dword ptr [ebx]
:00402820 53 push ebx --- main window handle as before
:00402821 FF159E374000 Call dword ptr [0040379E] --- GetDlgItemTextA
:00402827 A3B5264000 mov dword ptr [004026B5], eax --- Save the string length
Now I cheated just a little here :-) I saved all this then opened it in uedit and cut and paste in the bytes from my IP generator code, saved it, reloaded it and then simply edited the memory addresses in Uedit. So we end up with this:
:0040282C 33C0 xor eax, eax
:0040282E 33DB xor ebx, ebx
:00402830 33C9 xor ecx, ecx
:00402832 BF00274000 mov edi, 00402700
:00402837 8A040F mov al, byte ptr [edi+ecx]
:0040283A 3C39 cmp al, 39
:0040283C 7704 ja 00402842
:0040283E 3C30 cmp al, 30
:00402840 7322 jnb 00402864
:00402842 3C2E cmp al, 2E
:00402844 7404 je 0040284A
:00402846 3C00 cmp al, 00
:00402848 7513 jne 0040285D
:0040284A C1E308 shl ebx, 08
:0040284D C605B926400003 mov byte ptr [004026B9], 03
:00402854 B201 mov dl, 01
:00402856 A3BD264000 mov dword ptr [004026BD], eax
:0040285B EB0F jmp 0040286C
:0040285D 61 popad
;*****************************************
:0040285E E9FBF0FFFF jmp 0040195E --- obviously we cannot return as we did not call
:00402863 90 nop --- so I replaced this with the jump
;*****************************************
:00402864 2C30 sub al, 30
:00402866 C1E008 shl eax, 08
:00402869 41 inc ecx
:0040286A EBCB jmp 00402837
:0040286C C12DBD26400008 shr dword ptr [004026BD], 08
:00402873 A19FBD2600 mov eax, dword ptr [0026BD9F]
:00402878 F6E2 mul dl
:0040287A 02D8 add bl, al
:0040287C 86C2 xchg dl, al
:0040287E F625C2264000 mul byte ptr [004026C2]
:00402884 86C2 xchg dl, al
:00402886 FE0DB9264000 dec byte ptr [004026B9]
:0040288C 75DE jne 0040286C
:0040288E 33C0 xor eax, eax
:00402890 41 inc ecx
:00402891 3B0DB5264000 cmp ecx, dword ptr [004026B5]
:00402897 7C9E jl 00402837
:00402899 891DC6264000 mov dword ptr [004026C6], ebx --- save our converted IP Address
:0040289F E80FF3FFFF call 00401BB3 --- the normal IP function
:004028A4 61 popad --- reset all and
:004028A5 E9B4F0FFFF jmp 0040195E --- leave.....
Now we still have some problems to sort out before we can make our redirection to this code, we have to make sure that the normal IP processing function now uses our IP Dword not the local one from your machine.
For the window output function:
:00401C73 FF35C6264000 push dword ptr [004026C6]
For the URL creation routine:
:00401CB4 BEC6264000 mov esi, 004026C6
:00401CB9 90 nop
Now all that remains is to redirect to our code and we are all
systems go.
I have to admit that I screwed up a little here but then I am getting
a little tired now , I do not have enough bytes after the normal
button compare to make the jump into my new code. So I added the
following to the end of my previous code:
:004028AA 3D00FF0000 cmp eax, 0000FF00
:004028AF 0F854BFFFFFF jne 00402800
:004028B5 E963F0FFFF jmp 0040191D
To replace the normal compare and then changed:
:00401916 E98F0F0000 jmp 004028AA
That's all there is to it. The URL generated is correct but the IP address in the IP_Agent window does not update and of course IP_Agent still shuts down after you press the button, but hey! you would be furious if I didn't leave you something to do eh?
Hope this essay has something useful for you, it turned out to be an epic in the end still I think it covers some useful stuff I for one have never had to add a control without having a dialog box to place it in before. So at least I learnt something new.
This really is the end this time......
Essay
by: Harlequin
Page
Created: 27th January 2001