Using softice isnt just bpx hmemcpy


Written by NoodleSpa

Reason: /me tired of stupid questions about theese tings

Tools:

Lets say you wanna put a breakpoint but nothing hits :~( or you find that you just wanna scan for some string or data, well this is a better way to do it than the regular bpx whatever and then s 030:0 l ffffffff 'blah' we will use mIRC32 as an example.

Command: map32
Usage: map32 mirc32
Output:


:map32 mirc32                                                                   
Owner   Obj Name  Obj#  Address        Size      Type                         
MIRC32  CODE      0001  0157:00401000  000F0000  CODE  RO                     
MIRC32  DATA      0002  015F:004F1000  00035000  IDATA RW                     
MIRC32  .tls      0003  015F:00526000  00001000  IDATA RW                     
MIRC32  .rdata    0004  015F:00527000  00001000  IDATA RO SHARED              
MIRC32  .INIT     0005  015F:00528000  00002000  IDATA RO                     
MIRC32  .idata    0006  015F:0052A000  00001000  IDATA RW                     
MIRC32  .edata    0007  015F:0052B000  00001000  IDATA RO                     
MIRC32  .reloc    0008  015F:0052C000  00016000  IDATA RO SHARED              
MIRC32  .rsrc     0009  015F:00542000  0002D000  IDATA RW SHARED           

This gives us a listing of the sections in the .exe and what kind they are and where the process is mapped in virtual memory.

We want this because we don't wanna waste time searching the entire address space - we can see that the process starts at 401000 and ends at 542000 + 2d000 (we have to add the size of the last section to know exactly how long it is). A small note is that the process actually starts at 400000 but there is a 1000 byte header section at its beginning which is not included in the softice output.

we find out the length by typing this in softice:
:? 542000+2d000
0056F000 0005697536 "Vð "

the output is 0056F000 wich is the address at which the process ends we then substract the so called imagebase (which is where the process actually starts, and that is at 00400000) like this:

:? 56f000-400000
0016F000 0001503232 "ð "

We now have the length of the process and it is 0016F000

But we aren't in the correct context, and what is a context you might ask... well all processes (and even threads) have their own context, a context is like an environment, in this environment there are of course the CPU registers you see at the top of softice (EAX EBX and so on), and there is also 4 Gb of address space. Now you may wonder how all processes can have their own 4 gigabytes of space, it doesnt really make sense now does it :)

Well they can becasue of something called Virtual Machines and Virtual Address space. The process doesn't really have 4Gb until it actually demands it, and most processes never do that because it would slow down the computer a bit, and its also quite hard to make use of such a vast amount of space.(f0dder note: no it is not ;)

I wont go into this now becuse this is the minitut, but i might write about it later. (f0dder note: look at intel's pentium3 documents, look for "paging"). For now we are happy to have learned the map32 command and how to use the softice calculator. But you should know that every virtual machine (process or thread that is running) has its own context, which is simply a number or name if you will that windows use to keep track of what each register in that particular process/thread contains. Each process also has a handle and an ID and a thread also has a handle and an ID. All of this is mainatined by windows so it can keep track of each process and what it is doing.

The proc command is also very nice.
Command: proc
Usage: proc mirc32
Output:


:proc mirc32 
Process  pProcess  ProcessID  Threads   Context   DefHeap   DebuggeeCB         
Mirc32   8180B9F0  FF03AEDD   00000003  C10D2B50  00570000  00000000          

You can see that this also give a lot of info on the process, what we are interested in is the context handle. we are gonna use it to view a context (the one that mirc32 is in) without actually breaking into mirc32 with a breakpoint. for this we use a different command:

Addr
Usage: Addr contexthandle processname


:addr c10d2b50 mirc32      

You have to do the proc command before this otherwise you wont have a correct context handle, the context handle will be different every time you run mIRC32.

Now do this in softice: d 400000

If you look at your data window you will see that it says mIRC32

now type u 401000
you will now see the code section of mIRC32 in your code window softice will look kinda like this:


EAX=00000004   EBX=CE520070   ECX=00000000   EDX=00001862   ESI=C1094F80        
EDI=C00034C0   EBP=CE179F70   ESP=CE179DA0   EIP=C0008CF8   o d I s Z a P c     
CS=0028   DS=0030   SS=0030   ES=0030   FS=0078   GS=0030                       
-----MIRC32---------------------------------------byte--------------PROT---(0)--
0030:00400000 4D 5A 50 00 02 00 00 00-04 00 0F 00 FF FF 00 00  MZP.............
0030:00400010 B8 00 00 00 00 00 00 00-40 00 1A 00 00 00 00 00  ........@.......
0030:00400020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0030:00400030 00 00 00 00 00 00 00 00-00 00 00 00 00 01 00 00  ................
0030:00400040 BA 10 00 0E 1F B4 09 CD-21 B8 01 4C CD 21 90 90  ........!..L.!..
0030:00400050 54 68 69 73 20 70 72 6F-67 72 61 6D 20 6D 75 73  This program mus
0030:00400060 74 20 62 65 20 72 75 6E-20 75 6E 64 65 72 20 57  t be run under W
0030:00400070 69 6E 33 32 0D 0A 24 37-00 00 00 00 00 00 00 00  in32..$7........
-------------------------------------------------------------------------PROT32-
0028:00401000  A163104F00          MOV       EAX,[004F1063]
0028:00401005  C1E002              SHL       EAX,02
0028:00401008  A367104F00          MOV       [004F1067],EAX
0028:0040100D  57                  PUSH      EDI
0028:0040100E  51                  PUSH      ECX
0028:0040100F  33C0                XOR       EAX,EAX
0028:00401011  BFEC185000          MOV       EDI,005018EC
0028:00401016  B964595200          MOV       ECX,00525964
0028:0040101B  3BCF                CMP       ECX,EDI
0028:0040101D  7605                JBE       00401024
0028:0040101F  2BCF                SUB       ECX,EDI
0028:00401021  FC                  CLD
0028:00401022  F3AA                REPZ STOSB
0028:00401024  59                  POP       ECX
0028:00401025  5F                  POP       EDI
0028:00401026  6A00                PUSH      00
0028:00401028  E81A0D0000          CALL      00401D47
0028:0040102D  59                  POP       ECX
0028:0040102E  682C104F00          PUSH      004F102C
0028:00401033  6A00                PUSH      00
0028:00401035  E835F60E00          CALL      KERNEL32!GetModuleHandleA
0028:0040103A  A36B104F00          MOV       [004F106B],EAX
0028:0040103F  6A00                PUSH      00
0028:00401041  E9D6C90000          JMP       0040DA1C
0028:00401046  E9970D0000          JMP       00401DE2
0028:0040104B  33C0                XOR       EAX,EAX
------------------------------------MIRC32!CODE---------------------------------

Now type: :s 400000 l 16f000 'Borland' and this will appear in your data window:


-----MIRC32!DATA----------------------------------byte--------------PROT---(0)--
0030:004F1000 42 6F 72 6C 61 6E 64 20-43 2B 2B 20 2D 20 43 6F  Borland C++ - Co
0030:004F1010 70 79 72 69 67 68 74 20-31 39 39 36 20 42 6F 72  pyright 1996 Bor
0030:004F1020 6C 61 6E 64 20 49 6E 74-6C 2E 00 00 00 18 50 00  land Intl.....P. 
0030:004F1030 60 18 50 00 60 18 50 00-90 18 50 00 01 00 00 00  `.P.`.P...P..... 
0030:004F1040 00 00 00 00 98 37 4A 00-04 20 42 00 2C 20 42 00  .....7J.. B., B. 
0030:004F1050 00 00 00 00 BC 00 50 00-00 EC 10 50 00 84 11 50  ......P....P...P 
0030:004F1060 00 00 01 00 00 00 00 00-00 00 00 00 00 40 00 00  .............@..
0030:004F1070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

Now this is nice, let us try to expand a little on this trick, type map32 mIRC32 and you wil get the same list as above


Owner     Obj Name  Obj#  Address        Size      Type                         
MIRC32    CODE      0001  0157:00401000  000F0000  CODE  RO                     
MIRC32    DATA      0002  015F:004F1000  00035000  IDATA RW                     
MIRC32    .tls      0003  015F:00526000  00001000  IDATA RW                     
MIRC32    .rdata    0004  015F:00527000  00001000  IDATA RO SHARED              
MIRC32    .INIT     0005  015F:00528000  00002000  IDATA RO                     
MIRC32    .idata    0006  015F:0052A000  00001000  IDATA RW                     
MIRC32    .edata    0007  015F:0052B000  00001000  IDATA RO                     
MIRC32    .reloc    0008  015F:0052C000  00016000  IDATA RO SHARED              
MIRC32    .rsrc     0009  015F:00542000  0002D000  IDATA RW SHARED     

Now if we can see which section the string we searched for was found in, and we can decide if its likely to be the correct match of the search. But what if it wasnt found in the process memory? Just because a string isn't inside the actual process doesnt meen that it can't be accessed by the process, remember that each process have the possibility of accessing 4gb of virtual address space :=) But for a process to use space that isnt part of the actual mapped process it needs to allocate space.

Now, how do we find space allocated by a process? it could be almost anywhere and searching the entire space can be quite futile, and may give a lot of false hits if the string we need is a common one. No need to worry though, softice provides a nice command for these situations:

Command: Heap32
Usage: Heap32 <process>
Output:


:heap32 mirc32     

Heap: 00570000  Max Size: 1028K  Committed: 20K  Segments: 1
Address   Size
00570078  00000C7C
00570CF8  00000078
00570D74  0000003C
00570DB4  00000014
00570DCC  00000078
~~~~~~~~~~~~~~~~~~
lots of entries
~~~~~~~~~~~~~~~~~~
00670FBC  0000000C
00670FCC  0000001C
00670FEC  00000010
Used: 16K  Free: 1011K

Now this will produce quite long list on some applications, but dont worry too much about that, look at the first entry 00570078 and the last one 00670fec. This tells us that mIRC32 is using space that is outside of the process, allocated space :) now all we have to do in case we dont find our string in our process space, is to search the allocated space, the easiest way is just to put first entry in the list as start address and the length to the difference between them.

If you actually look at the entrie you will notice a pattern, some of them are at 0057xxxx and the others are at 0067xxxx, you might also have this divided kind of thing, it simply means that the memory was allocated as 2 main chunks, the first one starts at 00570000 and the second starts at 00670000. We won't go into memory allocation any further at this point, maybe another day. now lets continue

Make sure you switch to the mIRC32 context, (use the proc and addr commands) and then type d 570000 (you should of course use the address you find in your own heap32 list of mirc32). You can now view what mIRC32 keeps in its allocated space. This space can be searched just like the process memory and of course you can put breakpoints on when the allocated memory space is read from or written to.

Oh well, thats all from me now, I hope you find some use for this, I know I wouldn't wanna live without theese commands, and even if some of you may think of them as a waste of time, I can promise that there are times when they make life a lot easier (and apart from that you may actually wind up learning a bit about how programs actually look in memory and what they can and can not do)

Well, off you go then... good luck, and have a nice day

NoodleSpa

Article hosted by f0dder(a)yahoo.com (f0dder.cjb.net), last edit at 2001-07-19.