                                                             [Image][Image]

          The following article will be published in VIRUS
          BULLETIN,
          Virus Bulletin Ltd, England, Tel: +44 1235 555139
          Legalese: No part of this page may be reproduced,
          stored in a retrieval system or transmitted in any form
          without the prior written permission of the author,
          Eugene V. Kaspersky.
          -------------------------------------------------------

                               ZHENGXI Virus

          The ZHENGXI virus is a memory resident parasitic EXE
          and OBJ files infector, polymorphic and stealth. It
          also inserts COM-droppers into ZIP, ARJ and RAR
          archives including self-extracting EXE-archives.

          It is 7K of length and very complex virus, maybe the
          most complex virus I've ever seen. That virus infects
          EXE-files, and it does it in two different ways: while
          infecting the virus either infects the file by standard
          parasitic way (modify the header, and write the virus
          code at the file end), or scans EXE file body for C or
          Pascal-like subroutines, overwrites such subroutine
          with virus loader, and writes the original C/Pascal
          routine and the encrypted virus code to the file end.

          Then, the virus inserts its code into OBJ-files. Being
          linked these files may spread the virus as well as
          infected EXE-files. Then, that virus appends the
          infected COM droppers to the ZIP, ARJ, and RAR
          archives.

          All in all, that virus uses four types of infection:
          EXE appending, EXE inserting, OBJ infecting, and COM
          droppers. That virus seems to be "all-in-one",
          collecting lot of ideas that appeared in different
          viruses - infection of OBJ files (SHIFTER virus),
          archives (DEMENTIA), inserting into C/Pascal-routines
          (LUCRETIA).

          The most complex decryption routine known to me appears
          while looking through the code of infected EXE program.
          It looks like decryption routine of SMEG engine, but
          much, much enhanced - there are lot of calls to junk
          subroutines, CP/M and INT 21h functions, including
          direct calls to Interrupt Vectors Table. Then, the
          decryption loop covers another one - the virus is
          encrypted with two very complex polymorphic loops. The
          summary length of these loops is more than 2K in the
          sample of the virus that I received.

          After carrying through all these subroutines, tons of
          junk instructions and calls to DOS functions, the virus
          body appears in clear. And the text strings appear in
          the virus body:

           Abnormal program termination
           The Virus/DOS 0.54  Copyright (c) 1995 Zhengxi Ltd
           Warning! This program for internal use only!

          Troubles

          The style of writing the code in ZHENGXI virus is so
          hard, that it is very difficult to find out the purpose
          of more than hundred of the subroutines, and several
          hundred of the branches. The virus uses two different
          types of references to the same data (direst address
          access - CS:[address], and indexed access -
          SS:[BP+offset]). In some cases the virus uses first
          variant of addressing, in other cases - the second one,
          and even very good disassemblers cannot build reference
          tables that are so useful while analyzing of virus
          code.

          The virus also uses "hidden" branches, and it is not
          easy to find the destination address of the branch
          because there may be different destination addresses.

          And the last hit is using of CRC to check different
          conditions to perform the branch. CRC method to check
          the data is used by the virus in different cases: while
          installing, checking the file names and file headers,
          patching some active programs, and so on.

          For example, the virus pays special attention to
          several files, but does not contain the file names in
          clear in the virus code. The virus contains only CRC
          words (2 bytes) for each of the names. While accessing
          to a file the virus calculates the CRC sum of first 5
          symbols of the file name, and compares it with the CRC
          words. So, 5 symbols of file name are "packed" to two
          bytes of CRC sum. I have written the reverse routine,
          and the result was about 25.000 variants of the names.
          The output file occupies more than 400K of disk space!
          Looking through these names I found 11 from 16 names:

            1  UUENC   - UUENCODE.EXE
            2  PKLIT   - PKLITE.EXE
            3  LZEXE   - LZEXE.EXE
            4  NDD.E   - NDD.EXE (Norton Disk Doctor)
            5  DIET.   - DIET.EXE
            6  AFD.E   - AFD.EXE
            7  SD.EX   - SD.EXE (SpeedDisk)
            8  SPEED   - SPEEDDSK.EXE
            9  DEFRA   - DEFRAG.EXE
           10  TLINK   - TLINK.EXE , but there is another variant "AVSCA" - AVSCAN.EXE
           12  LINK.   - LINK.EXE

          Five names were not identified. There are a lot of
          possible names, there may be the names of some
          utilities I never heard before, so I cannot identify
          them. For example, some of the "readable" variants for
          these names:

           11: APPET CGAQW CPUOS FANTY GO.OF MSTST SETIM TARAV TMBRK TPPSA
           13: CCPUB GAPP1 SADIB SVCAP VKEYV
           14: FDARI FDLEV MTFFD PUEL. RAR3W SDNDW SLIP4
           15: CDHK. FMK91 FSIPO MSDKV NDA36 REL1. RUNNO
           16: KKBUG RTM32 SDSAT TDROM VADZZ VERT2

          Some of the names were found, and I started to find
          other CRCs in the virus body. At this moment I was
          faced with a more difficult task - the virus uses CRC
          sums while analyzing of the file header before
          infecting the file. There are the table with eight CRC
          sums in the virus body. The virus calculates the sum of
          first four bytes of the file header, and compares it
          with CRC, then calculates the CRC sum of first two
          bytes and compares with the same CRC table, then the
          sum of only the first byte of the file header.

          The reverse routine found very fast four of eight
          variants: one-byte variant of OBJ-header (80h), two
          two-bytes variants of EXE header ('MZ' and 'ZM'), and
          another two-bytes variant of ARJ-archive (60EAh). The
          rest was four four-bytes headers.

          To find these variants the reverse routine was working
          two days without break on my home PC-486/66. The result
          was 65.000 variants for each CRC sum. Source four bytes
          (unknown bytes) of file header are "packed" into two
          known bytes of CRC sum, so reversing brings 65.000
          variants of the source. The output files occupy about
          1Mb of disk space per each CRC sum!

          To finish that work that's enough just look through
          these megabytes and find four headers in 260.000
          variants (65.000 * 4). Fortunately, I was lucky and
          found two variants in a moment. First, the virus affect
          ARJ-files, so I've tried to find PKZIP file header.
          Success! 504B0304h string was found, that is header of
          PKZIP. Well are there other packers? I've tried RAR.
          Success! The RAR header "Rar!" was found in the
          variants.

          Then I've looked for different formats of different
          archives, executable files, but no success. Two of
          eight CRC sums are still not clear for me. I guess only
          that the first sum corresponds to some archive because
          the branch brings the control near the place where the
          virus affects ARJ, ZIP, and RAR archives, and that
          unknown routine uses the same subroutines that ARJ, ZIP
          and RAR infecting routines do. By the same reason I
          guess that second unknown header is the header of some
          OBJ-file - the virus brings the control near the
          routine that infects OBJ-files, and both ones use the
          same subroutines.

          Well, majority of the virus parts are identified, and
          that is the time for detailed analysis.

          Installation

          The code of the virus receives the control from
          different points depending on the infection way, but in
          all cases the destination is the polymorphic decryption
          routine. In EXE files (appending) the decryption
          routine receives the control immediately when EXE file
          is loaded into the memory for execution, in EXE files
          (inserting) - from the code of loader (see EXE
          infection), in the files linked with infected OBJ files
          - from CALL instruction (see OBJ infection), the COM
          droppers have JMP instruction at their beginnings, that
          JMP brings control to the decryption routine.

          Being decrypted, the installation routine of the virus
          receives the control. First, the virus moves its body
          to be aligned to paragraph (16 bytes). Then the virus
          hooks INT 1 (One Step Tracing), and traces INT 21h. The
          virus calls quite unusual function to do that - CP/M
          call 19h (Get Current Drive). The CP/M call brings the
          control to original DOS INT 21h handler after executing
          of some instructions, and the virus starts to trace
          original INT 21h code.

          Being traced the code of INT 21h handler is interrupted
          after each executed instruction. The virus receives the
          control, and calculates CRC sum (again that CRC!) of 12
          (0Ch) bytes of INT 21h code. If CRC is equal to one of
          two possible variants, the virus patches that code, and
          installs itself memory resident.

          It is absolutely impossible to find the variants of
          code that the virus looks for. The 12 bytes of code is
          packed to 2 bytes of first possible variants, and 2
          bytes of second one. As the result, reversing routine
          brings 2*10.000.000.000h, or more than
          2.000.000.000.000 variants of code. So the only way is
          to try different DOS in different modes (HIGH or LOW),
          and look at the INT 21h code patched by the virus.

          I found only one variant of the code that the virus
          looks for and patches, that is the part of INT 21h
          handler of DOS 5.x/6.x, the hexadecimal dump of that
          code looks as:

           06 1E 55 57 56 52 51 53 50 8C D8   (PUSH/PUSH/.../PUSH/MOV AX,DS)

          If such code is found, the virus checks several
          conditions before patching, and terminates installation
          in some cases:

            The virus       INT, AX              Terminates installation in
            checks                               case

            MS Windows      2Fh: 1600            Windows is installed
            installed

            Boot drive      21h: 3305            Boot drive is A: or B:

            INT 8, 13h,     direct access to     All these interrupts points
            28h             Interrupt Vectors    to the same segment (to exit
                            Table                installation if anti-virus
                                                 monitor is installed?)

            Host file       21h: 2Fh,1Ah,4Eh     File day is the same or near
            date (day       (Get/Set DTA,        the current day (two highest
            field)          FindFirst)           bits of current day number
                                                 XORed with file day is equal
                                                 to zero)

          If all listed above conditions meet the virus'
          requirements, the virus continues installation. It
          allocates the block of the system memory by DOS
          functions ChangeMem and AllocateMem (INT 21h, AH=4Ah,
          48h) for the virus TSR copy, then stores in its body 11
          bytes from the address of INT 21h handler that meet CRC
          sum, and patches INT 21h code with FAR CALL instruction
          (2F FF 1E ?? ??).

          What is the address of destination point of that FAR
          CALL? "Virus INT 21h handler", would say all virus
          experts. I thought the same, and I was wrong. The
          destination is INT 25h address (Absolute Disk Read).

          What is the surprise! The virus writes into INT 21h
          handler FAR CALL to INT 25h handler. Two absolutely
          different calls of different formats go to the same
          address.

          What is the next? The virus stores first five bytes of
          INT 25h handler and writes to there five bytes of FAR
          JMP to virus code. The result looks like follows:

                                  [Image]

          The virus places some "magic word" 06C7h just below
          CALL FAR to INT 25h address. I see no reason to make
          it, but only to hide the patch in disassembled code.
          The result of such patching looks like a plain code,
          without any strange commands.

          So, the virus has the same handler to intercept both
          INT 21h and INT 25h calls. To separate these calls the
          virus checks the address of caller (Caller_IP). If the
          call goes from INT 21h handler, the virus passes
          control to Virus INT 21h handler routine, in another
          case the Virus INT 25h handler receives the control.

          By the way, the virus does not check the system memory
          with any "Are you here?" call to avoid duplicate
          infection. The virus searches for specific code in INT
          21h handler and modifies that code. Being once
          installed into the system memory the virus cannot
          install itself more times because that specific code
          does not present in INT 21h handler any more.

          The installation routine is complete, the virus code is
          copied into new allocated block of the system memory,
          INT 21h and INT 25h are intercepted. But it is
          necessary to say that the virus can move its code to
          other memory blocks (see INT 21h handler analysis). So,
          the TSR copy of the virus does not occupy the same
          blocks of the system memory, but may move itself to
          other addresses, including UMB ones.

          Then the virus returns the control to the host program.
          There are three different variants of such return, they
          depend on the infection method. In case of COM dropper
          the virus only displays the message:

           Abnormal program termination

          and returns to DOS with Terminate function (INT 21h,
          AH=4Ch). In case of EXE-appending method of infection
          the virus restores the original file header by using
          polymorphic engine (generates polymorphic decryption
          routine, and executes it to restore original header,
          see EXE infection below). In case of EXE-inserting way
          the virus just returns to the host program because
          virus loader inserted into the file restores the
          original code by itself. In case of OBJ file the virus
          also just returns to the host program (see OBJ
          infection below).

          INT 21h Handler

          The virus intercepts 18 of INT 21h functions:

           3Dh, 6Ch - Open/Create File
           3Eh      - Close File
           3Fh      - Read File
           42h      - Lseek
           4Bh      - Execute File
           41h      - Delete File
           11h, 12h - FindFist/Next FCB
           4Eh, 4Fh - FindFist/Next ASCII
           00h, 4Ch - Terminate
           31h      - Stay TSR
           67h      - Set Handle Count
           48h, 49h, 4Ah - memory managing functions (Allocate, Free, Resize)

          The virus performs two actions for each of intercepted
          functions: when the virus receives the control, it
          checks the number of the function, and performs
          corresponding branch. Then it passes the control to
          original INT 21h handler, but makes it with CALL
          command instead of JMP. As the result the virus
          receives the control once more when original INT 21h
          handler completes the function and returns the control
          back to calling routine. At this moment the virus
          performs the call to second branch:

           Virus Handler:
             check function number
             call Routine_1            ; address depends on the function number
             call original INT 21h handler
             call Routine_2           ; address depends on the function number
             return

          Note1: then Routine_1 and Routine_2 will be used as
          identificators of routines that are called by the virus
          before, and after execution of INT 21h when
          corresponding INT 21h function is intercepted.

          Note2: The virus uses two ways to detect already
          infected files. First way is to check the file length.
          All files that are infected in such way have the file
          length that being divided to 9Dh gives the rest value
          25h.

          To detect already infected EXE files (appending) the
          virus checks another one condition. The virus gets CS,
          SS and SP register's values from EXE file header, then
          compares CS and SS, and checks SP register. In infected
          files the value of CS register is equal to SS+1, and SP
          register may have the value from 0080h till 008Fh.

          The Set Handle Count, Execute File and memory managing
          functions (AH=67h, 48h, 4Ah, 4Bh) are used by the virus
          to hide its code into the system memory - the virus
          manipulates with MCB blocks to be not visible on memory
          map while using memory browsing utilities. The virus
          "shows" its code in memory (Routine_1), executes INT
          21h call, and then again hides itself (Routine_2). As
          the result the virus is really invisible on memory map.

          While intercepting of Terminate, Stay TSR and
          FreeMemory functions (AH=0, 31h, 49h, 4Ch) the virus
          moves its code to new address in the system memory. The
          virus allocates new block of the memory (that may be
          conventional or UMB memory block), copies itself into
          there and redirect address of INT 25h for new location
          of the virus code. So, while installing the virus does
          not affect UMB blocks to place its TSR copy, but then
          it may move itself into UMB, and hide itself in there.

          While file opening (AH=3Dh, 6Ch) the virus performs two
          calls for both Routine_1 and Routine_2. Routine_1
          checks the opening mode, and if the file is opened for
          writing, the virus disinfects the file.

          Before disinfection the virus checks the file is
          accessed, and the program that accesses that file
          (caller). The virus checks the accessed file for being
          already infected. The virus does it by the file length
          (divide file length with 9Dh and compare the rest with
          25h), then checks is the file local or remote (the
          virus does not access the files on remote disks), and
          checks CS, SS and SP fields in EXE header. The virus
          compares the name of accessing program (caller) with
          the list of the names described in "Troubles", and does
          not disinfect accessed file if the name of accessing
          program is from that list.

          In case of AH=3D00h function (Open ReadOnly) the virus
          performs some strange actions. It scans the code of
          calling program (caller), and patches it. It looks like
          patching of some anti-virus scanner, or some another
          anti-virus utility. Fortunately, the virus has the bug,
          and that branch is never executed.

          The Routine_2 for Open function brings the control to
          stealth routine - the virus substitutes the file length
          with the original one in undocumented System File Table
          of that file.

          While reading from the file (AH=3Fh) the virus calls
          the stealth routine. In case of reading from header of
          infected file the virus reads, decrypts and copies
          original header into the reading buffer.

          While Lseek function (AH=42h) brings the control to
          another one stealth routine of the virus - the virus
          does not allow to seek out of original file length.

          While deleting of infected file (AH=41h) the virus
          disinfects it.

          While searching for the files (AH=11h, 12h, 4Eh, 4Fh)
          the virus substitutes the file length with the original
          one if the file is infected. The virus separates
          infected and not infected files by the same way as
          while file opening.

          FindFist/Next ASCII calls are also used by the virus to
          catch the files for infection. The virus saves the name
          of any file that is accessed with FindFirst function,
          and approximately each 5th file (with probability 3/16)
          accessed with FindNext function. The virus has only one
          buffer for the file name, so each next name overwrites
          previous one.

          While closing of any file (AH=3Eh) the virus checks and
          infects the file with the name that is stored in the
          buffer. The virus also infects the file that is closed,
          but is does it with probability 1/4 (by the result of
          virus' random generator)

          Infection

          Before infecting the file the virus checks several
          conditions:

             * the file is not "just creates" by comparing
               current day number with the file date and time
               stamp of the file (the same as while installing)
             * the file is local, and not on A: or B: drive
             * the file name is not *.?V? (*.OVL ?)
             * there is enough of free disk space (checks with
               INT 21h, AH=36h)

          In case of all these conditions the virus reads the
          file header and checks it with CRC method (see
          "Troubles"). I've found that the virus accesses three
          types of the files: EXE, OBJ, and archives.

          It is necessary to say that infection routine can
          receive as input any file, so the virus pays attention
          for internal file structure. The virus checks not only
          the file header, but then while infecting it checks
          other points and fields of the file to prevent
          corrupting of data files.

          Infecting EXE Files

          The most interesting way is used by that virus while
          infecting EXE files. The virus infects EXE by three
          different methods - appending, inserting, and infecting
          archives in self-extracting files.

          First, the virus checks the file structure, and if it
          is self-extracting EXE file (created with ZIP2EXE, for
          example), the virus infects attached archive (ZIP, ARJ,
          RAR) by the method that is described below - creates
          COM dropper, and adds it to the contents of the
          archive.

          Then the virus checks the file length, and does not
          infect the files with the length lesser than 400h
          (1024) bytes. The virus checks some other fields in EXE
          header, such as number of relocation, stamps of file
          packers (PKLITE, the virus infects PKLITEd files), and
          the EXE module length fields. If the length of the
          loadable module (note: not the length of the file) is
          larger that 32K, the virus inserts its loader into the
          file middle. In another case the virus infects the file
          by appending method.

          While infecting the files by appending method the virus
          reads file header, encrypts and saves it to the end of
          the file. Then the virus runs its polymorphic
          generator, and saves encrypted virus body and the
          polymorphic loops to the file end. To finish infection
          the virus increases the file length to the value that
          being divided by 9Dh gives the rest 25h (to detect
          already infected files, see "INT 21h Handler" above),
          and modifies EXE header fields (registers and module
          length).

          It is necessary to say that the virus encrypts the
          original header of the host file with the polymorphic
          encryption loop, and that loop is different with the
          routine that is used while encrypting the virus body.
          I.e. the virus calls the polymorphic engine twice -
          while encrypting original EXE header, and while
          encrypting the main body.

          While execution of infected EXE file the decryption
          loops restores the main virus body except original file
          header. To return to the host program the virus has to
          decrypt the data that is encrypted with polymorphic
          engine. But engine generates random loops with random
          selected encryption functions. To solve that problem
          the virus stores initial values of random generator
          while encrypting the host data, and runs polymorphic
          generator with the same values while decrypting that
          data. As the result the generator brings the same code
          that was used while encrypting host data, and being
          executed that routine decrypts it.

          So, the virus calls its polymorphic engine once time
          more - while installing into the system memory (to
          decrypt original host data).

          Infecting EXE Files (Inserting)

          If the file length is above than 32K, the virus seeks
          to the beginning of EXE main module (just after EXE
          header), reads 6K of the code, and looks for C/Pascal
          routines in there. Usually C/Pascal routines begin from
          the same "header" that saves the BP register, and moves
          stack pointer SP to BP:

           C subroutine header          Pascal subroutine header
           55         PUSH BP           55              PUSH BP
           8B EC      MOV BP,SP         89 E5           MOV BP,SP

          By using the same CRC method the virus scans the code
          for that "headers". If that code is not found, the
          virus passes control to EXE appending infection routine
          that is described above. If such code is found, the
          virus scans the next 54h (80) bytes of code for RET or
          CALL FAR instruction (C3h, CBh, CFh, 9Ah, CAh, C2h) to
          prevent overlap of next subroutine, or relocated
          address (the word at that address is modified by DOS
          while loading EXE file for execution). If such code
          (RET or CALL FAR) is found, the virus exits from
          infection routine.

          Then the virus reads 54h bytes of that routine,
          overwrites it with code of virus loader, then encrypts
          the main virus body with polymorphic engine, and saves
          it to the file end. Then the virus encrypts with simple
          SUB function the original code of subroutine and the
          second part of the loader, and saves it to the end of
          the file. Then the virus writes to the end of the file
          the random data with the same way as while "appending"
          method of infection.

                                  [Image]

          Being executed the loader looks for the host file name
          by using Program Segment Prefix fields, opens the
          files, seeks to the file end, then reads, decrypts and
          executes the second part of the dropper. That part
          restores the patched subroutine, allocates the system
          memory (conventional or UMB), reads the main virus
          body, and passes the control to the decryption
          polymorphic loop. That loop decrypts the virus body,
          and passes the control to installation routine. The
          virus installs itself into the system memory, and
          returns the control to host program.

          That is very insidious way of infection. The code of
          the virus is hidden in the file, and there is no direct
          entry to the virus code from the file header. The virus
          inserts itself instead of some subroutine in the file.
          That subroutine may be "seldom-executed" one. For
          example, the subroutine that displays the error
          message. So the virus may "sleep" in such files for a
          long time, and then jump out and infect the system
          under some limited conditions.

          Infecting Archives

          In case of archive the virus creates in memory the
          image of infected COM dropper, and appends it to the
          archive. That COM droppers always begins with JMP
          instruction followed by random data, encrypted virus
          code and decryption polymorphic loop. The JMP
          instruction brings the control to decryption loop.

          The name of dropper is random selected and finished
          with .COM extension, for example:

          HAIF.COM, UCM.COM, DOO.COM, VLG.COM, and so on.

          While processing the archive fields the virus does not
          use any external utility, but fills by itself all
          necessary fields. The virus does not packs the dropper,
          but uses "stored" method - the virus is stored in
          archive "as is".

          The virus stops dropping the infected COM files into
          ZIP archive if there is any "stored" file inside of
          archive, or saves some specific values into fields of
          other archives, and also stops infection if these
          values are found within archive records. So the virus
          does not drop its copy into the same archive twice.

          Infecting OBJ Files

          While infecting OBJ modules the virus checks the fields
          of OBJ file, creates, and inserts into there new OBJ
          records containing the virus code that is encrypted
          with polymorphic loops.

          While scanning OBJ file the virus checks the code of
          OBJ file for C/Pascal subroutine "header" as well as
          while inserting into EXE files, and infects OBJ files
          only if that code is found. But in case of OBJ module
          the virus does not drops the code of loader into there,
          but overwrites the C/Pascal header with CALL
          instruction (E8xxxx).

          Being linked into executable file that CALL brings the
          control to the virus polymorphic decryption loop. That
          loop decrypts the virus code and passes the control to
          the virus installation routine. Before return to host
          program the virus restores C/Pascal header - it
          overwrites the CALL instruction with three bytes of C
          subroutine header (558BECh).

          As well as in EXE files (inserting) that CALL may never
          receive the control, and virus may sleep for a long
          time. But under some conditions the virus may jump out,
          and infect the system.

          The virus does not infect the same object module twice.
          While infecting the virus checks different fields of
          OBJ module. Being infected, these fields do not meet
          the requirements of the virus, and the same OBJ file
          cannot be infected twice.

          INT 25h Handler

          The next unusual routine is virus INT 25h handler.
          Receiving the control, that routine realizes stealth
          routine on INT 25h level. While accessing to directory
          entries the virus substitutes the file length with
          original ones, while reading the header of infected
          file the virus restores it, and brings in original
          form.

          The virus does not realizes 100% stealth on INT 25h
          level, of course. There are the ways to bypass virus'
          stealth routine. But if some anti-virus program reads
          the file contents by INT 21h DOS functions, then reads
          directory structure and then file contents by absolute
          INT 25h calls, the virus stays not visible.

          Trigger Routine

          There is only one trigger routine in virus code, except
          displaying the message while executing COM droppers.
          That routine may be executed while processing ZIP
          files. If the virus finds some record that is packed
          with "stored" method, it checks the ZIP file date and
          time stamp. If the year of last modification of that
          file is 1996 or more, the virus search for all files of
          all directories of all disks from C: till Z:, then
          deletes the files and whole subdirectory tree.

          While deleting the virus uses DOS calls FindFirst/Next,
          Set File Attribute, Delete, RemoveDir, and so on.
          -------------------------------------------------------
              Copyright 1996 Eugene V. Kaspersky - All Rights
                                 reserved.
                                  GV160296
