home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / 80x0393.zip / ANTIDBG.TXT < prev    next >
Text File  |  1993-03-30  |  17KB  |  425 lines

  1.                             Anti Debugging Tricks
  2.  
  3.                                      By:
  4.  
  5.                                   Inbar Raz
  6.  
  7.                  Assistance by Eden Shochat and Yossi Gottlieb
  8.  
  9.                                Release number 5
  10.  
  11.   Today's anti debugging tricks devide into two categories:
  12.  
  13.   1. Preventive actions;
  14.   2. Self-modifying code.
  15.  
  16.   Most debugging tricks, as for today, are used within viruses, in order to
  17. avoid dis-assembly of the virus, as it will be exampled later in this file.
  18. Another large portion of anti debugging tricks is found with software
  19. protection programs, that use them in order to make the cracking of the
  20. protection harder.
  21.  
  22. 1. Preventive actions:
  23. ----------------------
  24.  
  25.   Preventive actions are, basically, actions that the program takes in order
  26. to make the user unable to dis-assemble the code or trace it while running.
  27.  
  28. 1.1. Interrupt disable:
  29.  
  30.        Interrupt disable is probably the most common form of anti-debugging
  31.      tricks. It can be done in several ways:
  32.  
  33.    1.1.1. Hardware masking of interrupt:
  34.  
  35.             In order to avoid tracing of a code, one usually disables the
  36.           interrupt via the 8259 Interrupt Controller, addressed by read/write
  37.           actions to port 21h. The 8259 Interrupt Controller controls the IRQ
  38.           lines. This means that any IRQ between 0 and 7 may be disabled by
  39.           this action. Bit 0 is IRQ0, bit 1 is IRQ1 etc. Since IRQ1 is the
  40.           keyboard interrupt, you may disable the keyboard without the
  41.           debugger being able to bypass it.
  42.  
  43.           Example:
  44.  
  45.           CS:0100 E421           IN     AL,21
  46.           CS:0102 0C02           OR     AL,02
  47.           CS:0104 E621           OUT    21,AL
  48.  
  49.             Just as a side notice, the keyboard may be also disabled by
  50.           commanding the Programmable Peripheral Interface (PPI), port 61h.
  51.  
  52.           Example:
  53.  
  54.           CS:0100 E461           IN     AL,61
  55.           CS:0102 0C80           OR     AL,80
  56.           CS:0104 E661           OUT    61,AL
  57.  
  58.    1.1.2. Software masking of interrupt:
  59.  
  60.             This is quite an easy form of an anti-debugging trick. All you
  61.           have to do is simply replace the vectors of interrupts debuggers
  62.           use, or any other interrupt you will not be using or expecting to
  63.           occur. Do not forget to restore the original vectors when you are
  64.           finished. It is adviseable to use manual change of vector, as shown
  65.           below, rather than to change it using interrupt 21h service 25h,
  66.           because any debugger that has gained control of interrupt 21h may
  67.           replace your vector with the debugger's. The example shows an
  68.           interception of interrupt 03h - the breakpoint interrupt.
  69.  
  70.           Example:
  71.  
  72.           CS:0100 EB04           JMP    0106
  73.           CS:0102 0000           ADD    [BX+SI],AL
  74.           CS:0104 0000           ADD    [BX+SI],AL
  75.           CS:0106 31C0           XOR    AX,AX
  76.           CS:0108 8EC0           MOV    ES,AX
  77.           CS:010A 268B1E0C00     MOV    BX,ES:[000C]
  78.           CS:010F 891E0201       MOV    [0102],BX
  79.           CS:0113 268B1E0E00     MOV    BX,ES:[000E]
  80.           CS:0118 891E0401       MOV    [0104],BX
  81.           CS:011C 26C7064C000000 MOV    Word Ptr ES:[000C],0000
  82.           CS:0123 26C7064E000000 MOV    Word Ptr ES:[000E],0000
  83.  
  84.    1.1.3. Vector manipulation
  85.  
  86.              This method involves manipulations of the interrupt vectors,
  87.           mainly for proper activation of the algorithm. Such action, as
  88.           exampled, may be used to decrypt a code (see also 2.1), using data
  89.           stored ON the vectors. Ofcourse, during normal operation of the
  90.           program, vectors 01h and 03h are not used, so unless you are trying
  91.           to debug such a program, it works fine.
  92.  
  93.           Example:
  94.  
  95.           CS:0100 31C0           XOR    AX,AX
  96.           CS:0102 8ED0           MOV    SS,AX
  97.           CS:0104 BC0E00         MOV    SP,000E
  98.           CS:0107 2E8B0E3412     MOV    CX,CS:[1234]
  99.           CS:010C 50             PUSH   AX
  100.           CS:010D 31C8           XOR    AX,CX
  101.           CS:010F 21C5           AND    BP,AX
  102.           CS:0111 58             POP    AX
  103.           CS:0112 E2F8           LOOP   010C
  104.  
  105.    1.1.4. Interrupt replacement
  106.  
  107.             This is a really nasty trick, and it should be used ONLY if you
  108.           are ABSOLUTELY sure that your programs needs no more debugging. What
  109.           you should do is copy the vectors of some interrupts you will be
  110.           using, say 16h and 21h, onto the vectors of interrupt 01h and 03h,
  111.           that do not occur during normal operation of the program. If the
  112.           user wants to debug the program, he would have to search for every
  113.           occurance of INT 01, and replace it with the appropriate INT
  114.           instruction. This trick is very effective if used together with the
  115.           fact that the INT 3 intruction has a ONE BYTE opcode - 0CCh, which
  116.           can not be changed to any other interrupt.
  117.  
  118.           Example:
  119.  
  120.           CS:0100 FA             CLI
  121.           CS:0101 31C0           XOR    AX,AX
  122.           CS:0103 8EC0           MOV    ES,AX
  123.           CS:0105 26A18400       MOV    AX,ES:[0084]
  124.           CS:0109 26A30400       MOV    ES:[0004],AX
  125.           CS:010D 26A18600       MOV    AX,ES:[0086]
  126.           CS:0111 26A30600       MOV    ES:[0006],AX
  127.           CS:0115 B44C           MOV    AH,4C
  128.           CS:0117 CD01           INT    01                
  129.  
  130. 1.2. Time watch:
  131.  
  132.        This may be a less common method, but it is usefull against debuggers
  133.      that disable all interrupts except for the time that the program is
  134.      executed, such as Borland's Turbo Debugger. This method simply retains
  135.      the value of the clock counter, updated by interrupt 08h, and waits in an
  136.      infinite loop until the value changes. Another example is when you mask
  137.      the timer interrupt by ORing the value INed from port 21h with 01h and
  138.      then OUTing it back, thus disabling the IRQ0 - Timer interrupt. Note that
  139.      this method is usefull only against RUN actions, not TRACE/PROCEED ones.
  140.  
  141.      Example:
  142.  
  143.      CS:0100 2BC0           SUB    AX,AX
  144.      CS:0102 FB             STI
  145.      CS:0103 8ED8           MOV    DS,AX
  146.      CS:0105 8A266C04       MOV    AH,[046C]
  147.      CS:0109 A06C04         MOV    AL,[046C]
  148.      CS:010C 3AC4           CMP    AL,AH
  149.      CS:010E 74F9           JZ     0109
  150.  
  151. 1.3. Fool the debugger:
  152.  
  153.        This is a very nice technique, that works especially and only on those
  154.      who use Turbo Debugger or its kind. What you should do is init a jump to
  155.      a middle of an instruction, whereas the real address actually contains
  156.      another opcode. If you work with a normal step debugger such as Debug or
  157.      SymDeb, it won't work since the debugger jumps to the exact address of
  158.      the jump, and not to the beginning of an instruction at the closest
  159.      address, like Turbo Debugger.
  160.  
  161.      Example:
  162.  
  163.      CS:0100 E421           IN     AL,21
  164.      CS:0102 B0FF           MOV    AL,FF
  165.      CS:0104 EB02           JMP    0108
  166.      CS:0106 C606E62100     MOV    Byte Ptr [21E6],00
  167.      CS:010B CD20           INT    20
  168.  
  169.      Watch this:
  170.  
  171.      CS:0108 E621           OUT    21,AL
  172.  
  173.      Notice:
  174.  
  175.        This trick does NOT effect the run of the program in ANY debugger. Its
  176.      only use is to try to deceive the user into thinking another opcode is
  177.      used, while another is actually run.
  178.  
  179. 1.4. Check CPU Flags:
  180.  
  181.        This is a nice trick, effective against almost any real mode debugger.
  182.      What you should do is simply set the trace flag off somewhere in your
  183.      program, and check for it later. If it was turned on, a debugger runs in
  184.      the background...
  185.  
  186.      Example:
  187.  
  188.      CS:0100 9C             PUSHF
  189.      CS:0101 58             POP    AX
  190.      CS:0102 25FFFE         AND    AX,FEFF
  191.      CS:0105 50             PUSH   AX
  192.      CS:0106 9D             POPF
  193.  
  194.      In the middle of the program:
  195.  
  196.      CS:1523 9C             PUSHF
  197.      CS:1524 58             POP    AX
  198.      CS:1525 250001         AND    AX,0100
  199.      CS:1528 7402           JZ     152C
  200.      CS:152A CD20           INT    20
  201.  
  202. 1.5. Cause debugger to stop execution:
  203.  
  204.        This is a technique that causes a debugger to stop the execution of a
  205.      certain program. What you need to do is to put some INT 3 instructions
  206.      over the code, at random places, and any debugger trying to run will stop
  207.      there. It is best if used within a loop, as it is run several times.
  208.  
  209.      Example:
  210.  
  211.      CS:0100 B96402         MOV    CX,0264
  212.      CS:0103 BE1001         MOV    SI,0110
  213.      CS:0106 AC             LODSB
  214.      CS:0107 CC             INT    3
  215.      CS:0108 98             CBW
  216.      CS:0109 01C3           ADD    BX,AX
  217.      CS:010B E2F9           LOOP   0106
  218.  
  219. 1.6. Halt computer using stack:
  220.  
  221.        This trick is based on the fact that debuggers don't usually use a
  222.      stack space of their own, but rather the user program's stack space. By
  223.      setting the stack to a location in the middle of a code that does NOT use
  224.      the stack itself, any debugger that will try to trace the code will
  225.      overwrite some of the code by its own stack (mainly interrupt return
  226.      addresses). Again, CLI and STI are in order, and are not shown for the
  227.      purpose of the example only. They must be included, or you risk hanging
  228.      your computer wether a debugger is installed or not.
  229.  
  230.      Example:
  231.  
  232.      CS:0100 8CD0           MOV    AX,SS
  233.      CS:0102 89E3           MOV    BX,SP
  234.      CS:0104 0E             PUSH   CS
  235.      CS:0105 17             POP    SS
  236.      CS:0106 BC0B01         MOV    SP,010B
  237.      CS:0109 90             NOP
  238.      CS:010A 90             NOP
  239.      CS:010B EB02           JMP    010F
  240.      CS:010D 90             NOP
  241.      CS:010E 90             NOP
  242.      CS:010F 89DC           MOV    SP,BX
  243.      CS:0111 8ED0           MOV    SS,AX
  244.  
  245. 1.7. Halt TD386 V8086 mode:
  246.  
  247.        This is a nice way to fool Turbo Debugger's V8086 module (TD386). It is
  248.      based on the fact that TD386 does not use INT 00h to detect division by
  249.      zero (or register overrun after division, which is treated by the
  250.      processor in the same way as in the case of division by zero). When TD386
  251.      detects a division fault, it aborts, reporting about the faulty division.
  252.      In real mode (even under a regular debugger), a faulty DIV instruction
  253.      will cause INT 00h to be called. Therefore, pointing INT 00h to the next
  254.      instruction, will recover from the faulty DIV.
  255.  
  256.      Note: It is very important to restore INT 00h's vector. Otherwise, the
  257.      next call to INT 00h will cause the machine to hang.
  258.  
  259.      Example:
  260.  
  261.      CS:0100 31C0          XOR     AX,AX
  262.      CS:0102 8ED8          MOV     DS,AX
  263.      CS:0104 C70600001201  MOV     WORD PTR [0000],0112
  264.      CS:010A 8C0E0200      MOV     [0002],CS
  265.      CS:010E B400          MOV     AH,00
  266.      CS:0110 F6F4          DIV     AH
  267.      CS:0112 B8004C        MOV     AX,4C00
  268.      CS:0115 CD21          INT     21
  269.  
  270. 1.8. Halt any V8086 process:
  271.  
  272.        Another way of messing TD386 is fooling it into an exception.
  273.      Unfortunately, this exception will also be generated under any other
  274.      program, running at V8086 mode. The exception is exception #13, and its
  275.      issued interrupt is INT 0Dh - 13d. The idea is very similar to the
  276.      divide by zero trick: Causing an exception, when the exception interrupt
  277.      points to somewhere in the program's code. It will always work when the
  278.      machine is running in real mode, but never under the V8086 mode.
  279.  
  280.      Note: It is very important to restore the original interrupt vectors.
  281.      Otherwise, the next exception will hang the machine.
  282.  
  283.      Example:
  284.  
  285.      CS:0100 31C0          XOR     AX,AX
  286.      CS:0102 8ED8          MOV     DS,AX
  287.      CS:0104 C70634001301  MOV     WORD PTR [0034],0113
  288.      CS:010A 8C0E3600      MOV     [0036],CS
  289.      CS:010E 833EFFFF00    CMP     WORD PTR [FFFF],+00
  290.      CS:0113 B8004C        MOV     AX,4C00
  291.      CS:0116 CD21          INT     21
  292.  
  293. 2. Self-modifying code:
  294. -----------------------
  295.  
  296. 2.1. Encryptive/decryptive algorithm:
  297.  
  298.        The first category is simply a code, that has been encrypted, and has
  299.      been added a decryption routine. The trick here is that when a debugger
  300.      sets up a breakpoint, it simply places the opcode CCh (INT 03h) in the
  301.      desired address, and once that interrupt is executed, the debugger
  302.      regains control of things. If you try to set a breakpoint AFTER the
  303.      decryption algorithm, what is usually needed, you will end up putting an
  304.      opcode CCh in a place where decryptive actions are taken, therefore losing
  305.      your original CCh in favour of whatever the decryption algorithm produces.
  306.      The following example was extracted from the Haifa virus. If you try to
  307.      set a breakpoint at address CS:0110, you will never reach that address,
  308.      since there is no way to know what will result from the change. Note that
  309.      if you want to make the tracing even harder, you should start the
  310.      decryption of the code from its END, so it takes the whole operation
  311.      until the opcode following the decryption routine is decrypted.
  312.  
  313.      Example:
  314.  
  315.      CS:0100 BB7109         MOV    BX,0971
  316.      CS:0103 BE1001         MOV    DI,0110
  317.      CS:0106 91             XCHG   AX,CX
  318.      CS:0107 91             XCHG   AX,CX
  319.      CS:0108 2E803597       XOR    Byte Ptr CS:[DI],97
  320.      CS:010C 47             INC    DI
  321.      CS:010D 4B             DEC    BX
  322.      CS:010E 75F6           JNZ    0106
  323.      CS:0110 07             POP    ES
  324.      CS:0111 07             POP    ES
  325.  
  326. 2.2. Self-modifying code:
  327.  
  328.    2.2.1. Simple self-modification:
  329.  
  330.             This method implements the same principle as the encryption
  331.           method: Change the opcode before using it. In the following example,
  332.           we change the insruction following the call, and therefore, if you
  333.           try to trace the entire call ('P'/Debug or F8/Turbo Debugger), you
  334.           will not succeed, since the debugger will put its CCh on offset 103h,
  335.           but when the routine runs, it overwrites location 103h.
  336.  
  337.           Example:
  338.  
  339.           CS:0100 E80400         CALL   0107
  340.           CS:0103 CD20           INT    20
  341.           CS:0105 CD21           INT    21
  342.           CS:0107 C7060301B44C   MOV    Word Ptr [0103],4CB4
  343.           CS:010D C3             RET
  344.  
  345.           Watch this:
  346.  
  347.           CS:0103 B44C           MOV    AH,4C
  348.  
  349.    2.2.2. The Running Line (self-decrypting):
  350.  
  351.             This is an example of a self-tracing self-modifying code,
  352.           sometimes called 'The running line'. It was presented by Serge
  353.           Pachkovsky. It is a bit tricky in implementation, but, unlike
  354.           all other techiniques mentioned in this document, it is relatively
  355.           resistive to various protections of the vector table. In short, it
  356.           results in instructions being decoded one at time, thus never
  357.           exposing long code fragments to analisys. I will illustrate it
  358.           with the following (over-simplified) code example:
  359.  
  360.           XOR     AX, AX
  361.           MOV     ES, AX
  362.           MOV     WORD PTR ES:[4*1+0],OFFSET TRACER
  363.           MOV     WORD PTR ES:[4*1+2],CS
  364.           MOV     BP, SP
  365.           PUSHF
  366.           XOR     BYTE PTR [BP-1], 1
  367.           POPF
  368.           MOV     AX, 4C00H               ; This will not be traced!
  369.           DB      3 DUP ( 98H )
  370.           DB      C5H, 21H
  371.  
  372.    TRACER:
  373.  
  374.           PUSH    BP
  375.           MOV     BP, SP
  376.           MOV     BP, WORD PTR [BP+2]
  377.           XOR     BYTE PTR CS:[BP-1], 8
  378.           XOR     BYTE PTR CS:[BP+0], 8
  379.           POP     BP
  380.           IRET
  381.  
  382. ===============================================================================
  383.  
  384. Comments:
  385.  
  386. In order to save lines of code, I did not insert the CLI/STI pair before any
  387. vector change. However, it is adviseable to do this pair before ANY manual
  388. vector change, because if any interrupt occurs in the middle of your
  389. operations, the machine could hang.
  390.  
  391. An apology:
  392.  
  393. In previous releases of this article, a false example, as noted by Serge
  394. Pachkovksy, was posted. That was 2.2.2 - Manipulating the PIQ. Apperantly
  395. the posted source would not work under any circumstances. In return, Serge has
  396. presented the 'Running Line' technique.
  397.  
  398. Thanks to:
  399.  
  400. Eden Shochat, 2:401/100
  401.   and
  402. Yossi Gottlieb, 2:401/100.3
  403.  
  404. for helping me assembling this list.
  405.  
  406. Other acknowledgements:
  407.  
  408. Matt Pritchard, 80XXX echo
  409.  
  410. Serge Pachkovsky, Distributed Node (2:5000/19.19)
  411.  
  412. ================================================================================
  413.  
  414. Any comments, suggestions, ideas and corrections will be gladly accepted.
  415.  
  416. Author can be reached in one of the following ways:
  417.  
  418. Inbar Raz, 2:401/100.1                          {fidonet}
  419. Inbar Raz, 2:403/100.42                         {fidonet}
  420. nyvirus@weizmann.weizmann.ac.il                 {internet}
  421. uunet!m2xenix!puddle!2!403!100.42!Inbar.Raz     {UUCP}
  422. Inbar.Raz@p1.f100.n401.z2.fidonet.org           {internet<>FIDO gate}
  423. Inbar.Raz@p42.f100.n403.z2.fidonet.org          {internet<>FIDO gate}
  424.  
  425.