home *** CD-ROM | disk | FTP | other *** search
- dis86 - Interactive 8086 Disassembler
-
- (C) COPYRIGHT 1985, 86, 87 by James R. Van Zandt, ALL RIGHTS RESERVED
-
-
-
-
- You are encouraged to copy and distribute this program freely, provided:
-
- 1) No fee is charged beyond the actual cost for such copying and
- distribution.
-
- 2) It is distributed ONLY in its original, unmodified state.
-
- If you like this program, and find it of use, then your contribution of
- $25 will be appreciated. For installation on a network file server
- with any number of users, a contribution of $125 is requested. A
- current version program disk and printed documentation are available
- for $50. Send contributions to:
-
- James R. Van Zandt
- 27 Spencer Dr.
- Nashua NH 03062
- 603-888-2272
-
- SYNOPSIS
-
- ûDis86 is a full-screen, interactive disassembler of object code for
- the 8086, 8087, 8088, 80186, 80286, and 80386 (products of Intel), and
- the V20 and V30 (products of NEC). The 80386 disassemblies include 32
- bit operands and addresses. Dis86 implements the concept of a "current
- location" and allows use of the cursor keys to change it. Code can come
- from a .EXE file (in which case the file header is properly
- interpreted), any other file (assumed to have no header), or anywhere
- in main memory (0000:0000 - F000:FFFF). It can also read and write
- using absolute disk addresses (in which case the disk organization is
- shown). Dis86 can install changes, even in a .EXE file, making it a
- convenient way to install patches. Versions are available for the IBM
- PC (and clones) and Z-100.
-
-
- REVISION HISTORY
-
- 1.00 First publically released version.
- 1.10 Implemented s-i-b byte for 80386 code (previously omitted due to
- oversight).
- 1.11 Reversed bx+disp and bp+disp codes.
- 1.12 Installed F format.
- 1.13 Fixed several small disassembly errors, installed V command.
- Reversed bx+disp and bp+disp codes again...NOTE: description in
- preliminary 80386 manual is WRONG.
- 1.14 V command installed. Follows interrupts if disassembling from memory.
- 1.15 Minor style changes, V command copies expression to reply line.
- 1.20 Absolute disk address mode installed.
- 1.21 Eliminating trailing blanks in printout.
- 1.22 Following FAT entries.
- 1.23 Foreground and background colors may be set in IBM version.
- 1.24 Cloning - can write optional parameters into object code.
- 1.25 Foreground and background colors work in Z-100 version. ESC and ^C
- abort commands that request keyboard input. Correctly shows
- last cluster on disk.
- 1.26 Segment register menu pops up in corner rather than clearing
- entire screen. Beeps eliminated.
- 1.27 12-bit FAT entries can be entered as well as displayed.
- 1.28 The file header pops up in the bottom half of the screen.
- 1.29 pg up and pg dn page through the help display pages.
-
-
- STARTING THE DISASSEMBLER
-
- To disassemble a file, give the file name (optionally preceded by a path
- name) on the command line:
-
- A>dis86 foo.exe
-
- To disassemble from RAM, use an empty command line:
-
- A>dis86
-
- To disassemble using absolute disk addresses, specify only the disk on
- the command line:
-
- A>dis86 b:
-
- There are no command line switches.
-
-
- HEADER INFORMATION
-
- The information in the .EXE file header, or the organization of the
- disk in absolute disk address mode, will be displayed when the program
- is first run and in response to the H command (see below).
-
-
- DISPLAY SCREEN
-
- During disassembly, the screen will resemble the following:
-
- 0000:0100 e9 01 90 jmp 9104
- 0000:0103 55 push bp
- 0000:0104 8b ec mov bp,sp
- 0000:0106 83 ec 0e sub sp,0e
-
- ...
-
- 0000:012C 50 push ax
- 0000:012D b8 69 00 mov ax,0069
- 0000:0130 50 push ax
- 0000:0131 e8 e9 5c call 5e1d
- dis86 1.00 - A SHAREWARE software product (c) 1986, James R. Van Zandt
- >
- ... 0000:0100 0000:0100 0000:0100
-
- Lines 1 through 21 are the disassembled code. Each line starts with
- the current address, followed by the actual bytes being disassembled.
- The rest of the line is the assembly language equivalent, if any, of
- the code. The display for A (ASCII), B (byte), D (data), F (font), and
- U (File Allocation Table) formats is similar. All numbers are shown in
- hexadecimal.
-
- Line 22 is a message and prompt line showing, for example, the
- arguments needed for some commands. Line 23 has the prompt. Typed
- characters are echoed on the rest of this line. Line 24 has three
- addresses, which are the top three entries in the stack (see the
- 'cursor right' and 'cursor left' commands below).
-
-
- CURSOR KEYS
-
- The "current location" is the address displayed on the first line
- of disassembly. The cursor keys are used to adjust the current
- location.
-
- The up and down cursor keys (8 and 2 on the numeric pad) are used to
- move the current location a small amount. <up> moves by one line
- except in C (code) format, when it moves up by one byte. (Note that <up>
- and <down> are not inverses in this case.):
-
- <up> moves up by one line or byte (lower address)
- <down> moves down by one line (higher address)
-
-
- The <pg up> and <pg dn> keys (9 and 3 on the numeric pad) move the
- current location by larger amounts. In C (code) format, they move by
- 32 bytes. In the other formats, they move by 11 lines on the screen.
- They will not move the cursor out of the disassembly buffer.
- Otherwise, they are inverses.:
-
- <pg up> moves up by 32 bytes (lower address)
- <pg dn> moves down by 32 bytes (higher address)
-
-
- The above keys change only the current location. Other commands change
- the current location by potentially large amounts, but first save it in
- a stack. The top three addresses in the stack are shown in the command
- area at the bottom of the screen.
-
- If the instruction at the current location is a jump, call, or a
- reference to a data location, the cursor right key (6 on the numeric
- pad) will push the current location on the stack and go to the
- referenced location. If the disassembly is from memory, interrupts can
- also be followed. For a data reference, the disassembly format is
- changed to D (hex and ASCII). If disassembly is from disk using
- absolute disk references and the disassembly format is U (display File
- Allocation Table, or FAT), then the next FAT entry is followed.
-
- <right> follows a jump, call, interrupt,
- data reference, or FAT entry
-
- If disassembling a FAT, the next entry is followed, staying within the
- same FAT. If disassembling from an address above the last FAT, the
- disassembler assumes a directory entry is being displayed, finds the
- next FAT reference (displacement 1A from the beginning of the current
- directory entry, which begins on a 32 byte boundary), and follows it
- into the first FAT. Note that the disassembly format must be U before
- the disassembler will attempt to follow a FAT entry. The usual format
- for a directory entry would be D or A. The correct sequence in that
- case would be U <ret> <right>.
-
- The cursor left or left arrow key (4 on the numeric pad) will pop the
- last address off the stack. Note that right arrow followed by left
- arrow will return you to the same address, whereas left arrow
- (returning, let us say, to address X) followed by right arrow will only
- return you to the same address if there is an appropriate jump, call,
- or data reference at X.
-
- <left> pops address stack
-
- After using the right arrow or one of the commands A, B, C, D, F, or G
- (in the next section) to go to a new address, then using the left arrow
- key to pop the stack, you will sometimes want to return to the previous
- address. The stack no longer holds the address. However, the left
- arrow key saves the current location in a special "previous state"
- before popping the stack.
-
- To return to the address stored in the "previous state", type shift
- right arrow on a Z-100, or control right arrow on an IBM PC.
-
- <shift><right> returns to "previous state" (Z-100)
- <cntrl><right> returns to "previous state" (IBM)
-
-
- In summary, the unshifted keys on the numeric pad are:
-
- <home> top of file ^ up 1 line <pg up> up 32 bytes
- |
-
- <-- pop addr stack --> follow jump/call
-
- |
- <end> end of file v down 1 line <pg dn> down 32 bytes
-
-
- <ins> setup options
-
- On the Z-100, the four keys with arrows on them may be used in addition
- to the 2, 4, 6, and 8 on the numeric pad.
-
-
- LETTER COMMANDS FOR MOVING THE CURSOR
-
- There are seven letter commands to change the display format and/or
- disassembly address:
-
- A ASCII data
- B byte data (hex)
- D data (both hex bytes and ASCII)
- C code
- F font
- G goto
- U File Allocation Table entry
-
- These commands may be in upper or lower case. Each may be followed by:
-
- <ret> Only the display format changes.
-
- A <expression> <ret>
- The current location changes to the specified address.
-
- S <expression> <expression> <expression> <ret>
- The disassembler searches from the current
- address to the end of the buffer for the
- specified sequence of hex bytes. If an
- expression has a segment specified using the
- ':' operator (below), the segment is ignored.
-
- S T [string] <ret>
- The disassembler searches from the current
- address to the end of the buffer for the
- specified ASCII string. Cases are not
- distinct, and the high order bit is ignored.
- The string can also be introduced by a double
- quote.
-
- S R <expression> <ret>
- The disassembler searches from the current
- address to the end of the buffer for a
- reference (jump or call) to the specified
- address.
-
- An <expression> can involve any of these items:
-
- hex numbers (either upper or lower case letters)
- cs, ds, es, ss, fs, gs
- currently assumed segment register values
- $ current location
- @ offset of top address on the stack
- 'x' single characters
- "jkl;" multiple character strings
-
- ...and any of these operators:
-
- + - * / add, subtract, multiply, divide
- : separate segment and offset
-
- Note that G with no address is a noop.
-
- There are two ways to ask for a string search. For example,
-
- S T jones
-
- S "Jones"
-
- In the first search, cases are not distinct and the high order bit
- is ignored. In the second search, the high order bit must be 0 and
- the cases must match.
-
- In F format, one byte is shown per line, and each bit in that byte is
- represented by an astrisk. This is suitable for displaying fonts for
- video displays, which are uniformly 8 bits wide.
-
- In U (clUster number) format, bytes are displayed as File Allocation
- Table, or FAT entries. This format is ordinarily useful only when
- disassembling using absolute disk addresses. In that case, the
- disassembler will have determined how many clusters there are on the
- disk. If there are fewer than 4097, then 12 bit FAT entries are
- assumed. If there are 4097 or more, then 16 bit FAT entries are
- assumed. Each pair of 12 bit FAT entries obviously occupies three
- bytes. If the cursor is set on the third byte of a pair of 12 bit
- entries, or the second byte of a 16 bit entry, the disassembler
- displays some dashes to signal that it is skipping that byte.
- Otherwise, it starts by displaying the FAT entry that begins with that
- byte.
-
- There are many explanations of how File Allocation Tables work. One
- good one is in Ray Duncan's book "Advanced MSDOS" (Microsoft Press,
- 1986).
-
- OPTIONS
-
- The 'O' command or <ins> (0 on the numeric pad) bring up menus for
- changing setup options and allow the user to reset the disassembly
- window. Use <space> or <ins> to move to the next screen, or <esc> to
- return to disassembly. To save options for the next disassembly, use
- the K command (below).
-
- In the first options menu, use the right and left cursor keys or <ret>
- to change the entries. The first item shows the processor which is
- supposed to execute the code being disassembled. There is some
- conflict in op codes between the V20 and V30 on one hand and the 80286
- and 80386 on the other. That is, the two families use the same op
- codes for different instructions. Dis86 selects the instruction
- appropriate for the chip shown in this menu. In addition, instructions
- not implemented by the indicated chip will be flagged. The second item
- on the first menu lets the user specify 16 or 32 bit mode for the
- 80386. In the 16 bit mode the 80386 is similar to the 8086. In the 32
- bit mode arithmetic is performed in 32 bit registers and all address
- offsets are 32 bits. (The 80386 itself selects the mode based on a bit
- in the segment table entry for the code segment.) The last two items
- allow selection of the colors on an IBM color display.
-
- In the second options menu, change an entry by typing over it. The two
- items are the byte value which matches anything in a byte or character
- search (the "wild card" byte) and the number of bytes displayed on each
- line for the A, B, or D formats. The latter value can also be set
- using the W command.
-
- The last options display is a small map of the code being disassembled
- which will resemble the following:
-
- ds= -10
- cs=0000
- | ss=0960
- es= -10 |
- | cursor=0000:0453 |
- CCCCCCCCCCCCCCcccccccccccccc
- ^0000:0000
- ^0000:6144
-
- The Cs represent the code being disassembled. The capital Cs are the
- portion of code in the disassembly window (see discussion below). The
- assumed values for the segment registers, the current location (labeled
- "cursor"), and the beginning and end addresses of the disassembly
- window are also shown. The window can be adjusted using the right and
- left cursor keys.
-
- By using the <ins> key to enter the options menu and to step from one
- menu to the next, you can leave your right hand on the numeric pad.
-
-
- MISCELLANEOUS COMMANDS
-
- The 'E' command allows the user to modify the program being
- disassembled. Changes are initially made only in the disassembly
- buffer. Before the buffer is overwritten or the disassembler
- terminates, the user is asked whether the changes are to be written to
- the file or RAM area being disassembled. The values entered may be
- given in hex expressions or ASCII. Values too large to fit into a byte
- are assumed to be words or double words. Here are some examples:
-
- 45 67 'A' => 45 67 41
-
- 2ea+3 => ed 02
-
- 9c/3 => 34
-
- "Alpha Beta" 0d 0a => 41 6c 70 68 61 20 42 65 74 61 0d 0a
-
-
- The 'K' command (for "klone") is used to write the current values of
- these parameters into the disassembler object code:
-
- wild card byte in search pattern
- data bytes per line for A, B, and D formats
- processor code
- bit mode (for 80386 code)
- foreground color
- background color
-
- This will reset the default values of these parameters. (Note,
- however, that when neither a file nor a disk drive is specified, the
- bytes per line is always set to four so that the interrupt vectors in
- low memory are displayed one per line.) This command prompts for the
- name of the object code file, which should include the drive and
- directory unless the file is in the current directory or somewhere in
- the path. The default file name is "dis86.exe".
-
- The 'P' command is used to print a disassembly listing to a file. The
- first time this command is used, it prompts for a file name. The
- default file name is "printout". To actually send the listing to a
- printer, specify the filename "prn". If the file already exists the
- new information will be appended. The file is automatically closed
- before the disassembler exits. The command also prompts for the
- beginning and end addresses of the code to be printed. The default
- addresses print the current screen. When the printing is finished, the
- current address is advanced to the first byte not printed. Thus, you
- can repeat the sequence
-
- P <ret> <ret>
-
- to print a large section.
-
- Enter 'R' to display and/or change the assumed segment register values.
- Entries may be full expressions. For example, to copy the value from SS
- into DS, use the cursor keys to select the DS register and type
-
- ss <ret>
-
-
- The 'S' command selects a new segment register value for displaying
- addresses. The new register is shown on the message line. The actual
- address being disassembled is not changed (see "segmentation" below).
-
- The 'V' command requests an expression and displays its value.
-
- The 'W' command is used to set the number of bytes displayed on each
- line for the A, B, and D formats. This is useful for displaying
- tables. For example, when dis86 is executed without a file, it
- displays bytes starting at address 0000:0000 and the width is set to
- four so each interrupt vector is shown on a separate line.
-
- Type '?' to get a series of help screens. Type <esc> to return to the
- disassembly, or any other key to advance to the next screen
-
- Enter 'Q' to stop the disassembler and return to DOS.
-
-
- TYPING REQUESTED DATA
-
- Many commands supply default entries for requested data. If you decide
- to accept the default, just enter <ret>. For editing entries,
- you can position the cursor using the left and right cursor keys to
- move by one character, <home> (7 on the numeric pad) to move to the
- left end of the string, or <end> (1 on the numeric pad) to move to the
- right end. Use the <del> or <backspace> keys to delete incorrect
- characters, or just type characters to be inserted. (There is no
- "replace" typing mode.) In every case but one, you can also edit the
- default entry by making <right>, <end>, or <del> your first keystroke.
- The exception is the default for the byte search function.
-
- In edit mode, the four active keys on the numeric pad are:
-
- <home> start of string ^ <pg up>
- |
-
- <-- left one char --> right one char
-
- |
- <end> end of string v <pg dn>
-
-
- DISASSEMBLY WINDOW
-
- The disassembler uses a buffer to hold the code being disassembled.
- For most purposes, this disassembly window is transparent to the user.
- If the user requests an address within the file but outside the
- disassembly window, the appropriate code is automatically read in. The
- existence of the window is apparent in only three cases:
-
- 1. If the disassembler is started near the end of the window
- and reaches the end before it fills the screen, the
- rest of the screen will be left blank.
-
- 2. The searches are done only from the current location to the
- end of the buffer.
-
- 3. If the contents of the buffer has been changed (see 'E'
- command) the user is asked whether they should be
- written out before the buffer is overwritten or control
- is returned to DOS.
-
-
- LOAD ADDRESS
-
- Code from a .COM file is displayed as though its Program Segment Prefix
- were at 0000:0000 and its load address were 0000:0100.
-
- Code from a .EXE file is displayed as though its load address were
- 0000:0000. This puts its Program Segment Prefix is 10 paragraphs or
- 100 (hex) bytes lower. This is somewhat awkward, because the DS and ES
- registers are initialized to point to the PSP. The disassembler
- displays this segment value as -10. The advantage of a load address of
- 0000:0000 is that no relocation is necessary. The bytes displayed are
- exactly the same as those in the file. This also means that the code
- can be modified (see below for the 'E' command) and written back to the
- file without being "unrelocated".
-
-
- SEGMENTATION
-
- Addresses are displayed in segment:offset form, using the current
- assumed value of the current segment register. The current segment
- register can be selected using the 'S' command to step among the
- available registers (CS, SS, DS, ES, FS, and GS - the last two only with
- 80386 code). Changing segment registers or their values does not move
- the disassembler cursor. Only the displayed segment and offset values
- will change to reflect the new assumptions. A legal offset will be
- displayed as a four digit hex number (0000 to FFFF). Other offsets
- (negative, or greater than 64K) will also be calculated and displayed
- correctly, although they are illegal on the 8086. Illegal offsets will
- have more than four digits.
-
- The segment register values are initialized as indicated in the file
- header (for .EXE files) or to zero (for other files or RAM). The
- disassembler has no way of determining the values which may be set
- during execution. For example, the initialization code for DeSmet C
- programs reset DS to the same value as the initial SS before executing
- main().
-
- The assumed segment register values can be altered in two ways. Any
- segment register can be changed using the register menu reached by the
- 'R' command. In addition, when the right arrow key is used to follow a
- far call or jump, the new code segment value is loaded into the CS
- register. When the user specifies a new segment value on an A, B, C, D,
- or G command, that value is used for subsequent displays but none of the
- assumed segment register values is changed.
-
- The segmentation models of the protected modes of the 80286 and 80386
- are not supported.
-
-
- ALIGNMENT
-
- Dis86 will correctly disassemble code if started on the first byte of an
- instruction. If started in the middle of an instruction, it will
- disassemble that instruction and perhaps several more incorrectly. In
- this case the disassembler is said to be out of alignment with the
- object code. The disassembler will tend to correct its alignment if it
- continues long enough. 8086 instructions tend to be longer than, for
- example, those for the 8080, so the disassembler will tend to stay out
- of alignment for more bytes. Generally speaking, the alignment will be
- correct after the first half dozen lines.
-
-
- SUMMARY
-
- Here are all the letter commands:
-
- A nnnn ASCII data
- B nnnn byte date (hex)
- C nnnn code (disassembly)
- D nnnn data (hex and ASCII)
- F nnnn font
- E enter new data (follow with a series of hex expressions)
-
- G nnnn goto address nnnn
- H display file header information (for .EXE files only)
- K klone - write current parameters into object file
- O change setup options
- P print disassembly listing to file
- Q quit to DOS
-
- R change segment register values
- S select a new segment register
- V evaluates an expression
- W set bytes of data per line for A, B, and D formats
- X exchange current address (at top of screen) with top of stack
- ? display help screens
- / display list of alphabetic commands on message line
-
-
- EXAMPLE 1
-
- In the examples, <left>, <right>, <up>, and <down> refer to the four
- cursor keys (4, 6, 8, and 2 on the numeric pad, plus the four arrow
- keys on the Z-100 keyboard). <pg up> and <pg dn> refer to the 9 and 3
- on the numeric pad.
-
- To investigate the bootstrap code, type
-
- A>dis86 <ret>
-
- and press
-
- <space>
-
- to advance to the disassembly display, which will be a D (data) format
- display of the interrupt vectors. Next type
-
- c a ffff:0000 <ret>
-
- (for Code format at the Address ffff:0000). On an IBM, the ROM release
- date and machine ID appear in the last 16 bytes of the ROM. To see
- them, type
-
- D <ret>
-
- The release data is at addresses ffff:0005 - ffff:000c in ASCII. The
- machine ID is at ffff:000e. Some of the possible values are:
-
- ff IBM PC
- fe IBM XT and Portable IBM PC
- fd IBM PCjr
- fc IBM AT
- 2d Compaq
- 9a Compaq-Plus
-
- Return to code format by typing
-
- C <ret>
-
- One of the instructions displayed will almost certainly be a jump. If
- so, press
-
- <down>
-
- enough times to bring the jump to the top line, then
-
- <right>
-
- to follow the jump. Note that the previous addresses were pushed onto
- the stack, as shown on the bottom line. To return to the most recent
- address, press
-
- <left>
-
- To leave the disassembler, press
-
- Q
-
-
- EXAMPLE 2
-
- For a second example, let us disassemble the disassembler itself. Begin
- by typing
-
- A>dis86 dis86.exe <ret>
-
- Note the header information, including the entry point of 0000:0000 and
- the initial stack location of approximately 09e0:9eb8. Proceed to the
- disassembly screen by typing
-
- <space>
-
- The disassembler starts in C (code) format at the entry point, which is
- a jump to the initialization code. To follow the jump, type
-
- <right>
-
- One of the early instructions in the initialization code refers to the
- first location in the stack segment. Bring this location to the top of
- the screen by typing
-
- <pg dn> <down> <down>
-
- and follow the reference by typing
-
- <right>
-
- Since it was a data reference, the disassembler automatically switched
- to D (data) format. Also, the addresses are displayed using the value
- of segment register SS. Note that the two previous addresses have been
- pushed onto the stack, as shown at the bottom of the screen. Return to
- the most recent one by typing
-
- <left>
-
- The initialization code gets rather involved, but one of its functions
- is to initialize DS to the same value as SS. To reflect this, use the
- R command:
-
- R
-
- DS is the first register in the list, so you need only enter the
- appropriate value:
-
- ss <ret> <space>
-
- The code for the main program immediately followed the jump at
- 0000:0000. To return there, type
-
- <left>
-
- Send a copy of this screen to the file "printout" by typing
-
- P <ret> <ret> <ret>
-
- To inspect the data segment, type
-
- A ds:0 <ret>
-
- To display more characters on each line, use the W command:
-
- W 60 <ret>
-
- Use the search command to find one of the messages:
-
- G S T hime <ret>
-
- This string won't be found. To correct the spelling to "home" and try
- again, type
-
- G S T <right> o <del> <ret>
-
- Once again, leave the disassembler by pressing
-
- Q
-
-
- EXAMPLE 3
-
- The third example will show how the disassembler can be used to
- undelete a disk file. Begin by creating and deleting a short text file
- using redirection from the DOS prompt:
-
- A>type con >patriot.1
- Now is the time for all good men to come to the aid of their country.<ret>
- <cntl-Z> <ret>
-
- A>copy patriot.1 patriot.2
- A>erase patriot.1
-
- Now, start the disassembler by typing
-
- A>dis86 a:
-
- The disassembler first shows the disk header information, which for a
- 360 K floppy disk looks like this:
-
-
- Drive information for A:
- FD media descriptor byte
- 200H = 512 bytes/sector
- 400H = 1024 bytes/cluster
- 354 clusters, or 362496 bytes, for disk files
- Sector Offset (hex) Length (sectors)
- 0 0 1 BIOS parameters and boot code
- 1 200 2 FAT 1
- 3 600 2 FAT 2
- 5 a00 7 root directory with 112 entries
- 12 1800 2 cluster 2
- 718 59c00 2 cluster 355 (last)
-
-
- Note in particular the byte offsets of 200 to the first FAT and a00 to
- the root directory, and the cluster size of 400. Proceed to the first
- disassembly screen by typing
-
- <space>
-
- The disassembler starts in D (data) mode at the first sector, which is
- the boot sector. Now type
-
- D A a00
-
- to show the disk directory and
-
- W 8
-
- to set the display width to 8. Each directory entry takes four
- lines:
-
- 0000:0CA0 47 4c 49 20 20 20 20 20 |GLI |
- 0000:0CA8 43 20 20 20 00 00 00 00 |C ....|
- 0000:0CB0 00 00 00 00 00 00 65 79 |......ey|
- 0000:0CB8 5b 0f 6d 00 cd 2f 00 00 |[.m.M/..|
-
- The fields in each entry are as follows:
-
- 47 4c 49 20 20 20 20 20 |GLI |
- file name ^^^^^^^^^^^^^^^^^^^^^^^
-
- 43 20 20 20 00 00 00 00 |C ....|
- extension ^^^^^^^^
- attribute ^^
- reserved ^^^^^^^^^^^
-
- 00 00 00 00 00 00 65 79 |......ey|
- reserved ^^^^^^^^^^^^^^^^^
- time ^^^^^
-
- 5b 0f 6d 00 cd 2f 00 00 |[.m.M/..|
- date ^^^^^
- starting cluster ^^^^^
- file size in bytes ^^^^^^^^^^^
-
- It's the file name and the last two fields we'll be concerned with.
- Search for the files we just created using a wild card as the first search
- byte:
-
- G S ff "ATRIOT" <ret>
-
- The display should resemble this:
-
- 0000:0B00 e5 41 54 52 49 4f 54 20 |eATRIOT |
- 0000:0B08 31 20 20 20 00 00 00 00 |1 ....|
- 0000:0B10 00 00 00 00 00 00 0d a4 |.......$|
- 0000:0B18 8c 0f a2 00 47 00 00 00 |..".G...|
- 0000:0B20 50 41 54 52 49 4f 54 20 |PATRIOT |
- 0000:0B28 32 20 20 20 00 00 00 00 |2 ....|
- 0000:0B30 00 00 00 00 00 00 0d a4 |.......$|
- 0000:0B38 8c 0f a3 00 47 00 00 00 |..#.G...|
- 0000:0B40 00 e5 e5 e5 e5 e5 e5 e5 |.eeeeeee|
- 0000:0B48 e5 e5 e5 e5 e5 e5 e5 e5 |eeeeeeee|
- 0000:0B50 e5 e5 e5 e5 e5 e5 e5 e5 |eeeeeeee|
-
- The ONLY change in the entry for the PATRIOT.1 is that the first byte
- of the file name has been replaced by hex e5 (a lower case 'e' with the
- high order bit set). By looking at the third and fourth bytes of the
- last line, we see that the file started at cluster a2. From the
- next four bytes, we learn that the file had length 47 (hex) bytes.
- This is less than the cluster size of 400, so the file had only only
- cluster. Note that PATRIOT.2 has the same length, and starts at
- cluster a3.
-
- To examine the initial cluster of the file, type
-
- H
-
- to display the header information. Note that clusters have length 400
- and that cluster 2 starts at offset 1800. Switch to ASCII format and
- go to the beginning of the file by typing
-
- <ret>
- A A 1800+(a2-2)*400
-
- The display should look like this
-
- 0000:29800 |Now is t|
- 0000:29808 |he time |
- 0000:29810 |for all |
- 0000:29818 |good men|
- 0000:29820 | to come|
- 0000:29828 | to the |
- 0000:29830 |aid of t|
- 0000:29838 |heir cou|
- 0000:29840 |ntry... |
- 0000:29848 |DOC ....|
- 0000:29850 |.......5|
- 0000:29858 |..:.Og..|
- 0000:29860 |DIS86Z |
-
- The file information is present, although there appears to be some
- garbage following it.
-
- Each cluster has an entry in the File Allocation Table, or FAT. When a
- file is deleted, its clusters are marked as "free" by zeroing the
- corresponding entries in the FAT. Display the beginning of the FAT by
- typing
-
- U A 200
-
- To move to the FAT entry for cluster a2, type
-
- G A $+(a2*3)/2
-
- In my case, the display starts
-
- 0000:02F3 000 fff 000 000
- 0000:02F9 000 000 000 000
-
- The second entry, which corresponds to cluster a3 of PATRIOT.2, has the
- code for "last cluster". The first entry, which corresponds to cluster
- a2, is still zero so that file can be "undeleted". To do that, we
- change the entry to the value for "last cluster":
-
- E fff <ret>
-
- We have to make the same change in the other copy of the FAT. Recall
- that each FAT is 400 (hex) bytes long:
-
- G $+400 <ret>
- E fff <ret>
-
- To return to the directory entry type
-
- <left> <left> <left>
-
- At this point the disassembler must move its window so it asks our
- permission to write the changes to the disk:
-
- Y <ret>
- <left>
-
- Now, restore the first byte of the filename:
-
- E 'P' <ret>
-
- To leave the disassembler (and agree to write the directory change
- out), type
-
- Q Y <ret>
-
- To confirm that both files exist, ask for a directory listing
-
- A>dir pa*
-
-
- NOTES
-
- When there is more than one cluster in a file, the directory entry
- contains the number of the first cluster. The FAT entry corresponding
- to the first cluster contains the number of the second cluster. This
- chain of cluster numbers continues, with the FAT entry for the last
- cluster containing fff. DOS often allocates all the clusters together
- (making the file contiguous). For example, in this fragment of a FAT
-
- 0000:03CE 135 136 137 fff
- 0000:03D4 139 fff 13b 13c
- 0000:03DA fff 13e 13f 143
-
- there seems to be a file occupying the two clusters 138 and 139, and a
- second file occupying the three clusters 13a, 13b, and 13c. I say
- "seems" because it is not obvious from just this printout that cluster
- 138 (whose entry at 03d4 contains the pointer to 139) is actually the
- first cluster of a file. Only LAST clusters are explicitly marked in
- the FAT. To confirm that it is indeed the first cluster of a file, we
- could search the rest of the FAT and verify that nowhere was there a
- pointer to 138, or we could find the pointer to 138 in some directory
- entry.
-
- Longer files are more trouble to unerase, but are of course also more
- valuable. To calculate the length in clusters for a longer file we
- would use the V (evaluate) function. For example, for a 1345 byte file
- type:
-
- V 1345/400 <ret>
-
- The answer, 3, is the number of full clusters. Remember to add one for
- the partially filled cluster at the end. If there were four clusters
- in the file in the file you want to undelete, then there will be zeros
- in the four corresponding entries in the FAT. The directory tells you
- only where the first entry is. The other three entries could be
- literally anywhere else in the FAT, but since DOS assigns the next
- available cluster to a growing file, they can probably be found shortly
- after the first entry. Even if you find four zero entries in a row
- starting there, some of those free clusters could have belonged to some
- other deleted file. You still need to check the data in the clusters
- to be sure.
-
-
-