Function: highlight-confusing-reorderings

highlight-confusing-reorderings is an interactive and byte-compiled function defined in mule-cmds.el.gz.

Signature

(highlight-confusing-reorderings BEG END &optional REMOVE)

Documentation

Highlight text in region that might be bidi-reordered in suspicious ways.

This command find and highlights segments of buffer text that could have been reordered on display by using directional control characters, such as RLO and LRI, in a way that their display is deliberately meant to confuse the reader. These techniques can be used for obfuscating malicious source code. The suspicious stretches of buffer text are highlighted using the confusingly-reordered face.

If the region is active, check the text inside the region. Otherwise check the entire buffer. When called from Lisp, pass BEG and END to specify the portion of the buffer to check.

Optional argument REMOVE, if non-nil (interactively, prefix argument), means remove the highlighting from the region between BEG and END, or the active region if that is set.

Probably introduced at or before Emacs version 29.1.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/international/mule-cmds.el.gz
(defun highlight-confusing-reorderings (beg end &optional remove)
  "Highlight text in region that might be bidi-reordered in suspicious ways.
This command find and highlights segments of buffer text that could have
been reordered on display by using directional control characters, such
as RLO and LRI, in a way that their display is deliberately meant to
confuse the reader.  These techniques can be used for obfuscating
malicious source code.  The suspicious stretches of buffer text are
highlighted using the `confusingly-reordered' face.

If the region is active, check the text inside the region.  Otherwise
check the entire buffer.  When called from Lisp, pass BEG and END to
specify the portion of the buffer to check.

Optional argument REMOVE, if non-nil (interactively, prefix argument),
means remove the highlighting from the region between BEG and END,
or the active region if that is set."
  (interactive
   (if (use-region-p)
       (list (region-beginning) (region-end) current-prefix-arg)
     (list (point-min) (point-max) current-prefix-arg)))
  (save-excursion
    (if remove
        (let (prop-match)
          (goto-char beg)
          (while (and
                  (setq prop-match
                        (text-property-search-forward 'font-lock-face
                                                      'confusingly-reordered t))
                  (< (prop-match-beginning prop-match) end))
            (with-silent-modifications
              (remove-list-of-text-properties (prop-match-beginning prop-match)
                                              (prop-match-end prop-match)
                                              '(font-lock-face face mouse-face
                                                               help-echo)))))
      (let ((count 0)
            next)
        (goto-char beg)
        (while (setq next
                     (bidi-find-overridden-directionality
                      (point) end nil
                      (current-bidi-paragraph-direction)))
          (goto-char next)
          ;; We detect the problematic parts by watching directional
          ;; properties of strong L2R and R2L characters.  But
          ;; malicious reordering in source buffers can, and usuually
          ;; does, include syntactically-important punctuation
          ;; characters.  Those have "weak" directionality, so we
          ;; cannot easily detect when they are affected in malicious
          ;; ways.  Therefore, once we find a strong directional
          ;; character whose directionality was tweaked, we highlight
          ;; the text around it, between the first bidi control
          ;; character we find before it that starts an
          ;; override/embedding/isolate, and the first control after
          ;; it that ends these.  This could sometimes highlight only
          ;; part of the affected text.  An alternative would be to
          ;; find the first "starter" following BOL and the last
          ;; "ender" before EOL, and highlight everything in between
          ;; them -- this could sometimes highlight too much.
          (let ((start
                 (save-excursion
                   (re-search-backward reorder-starters nil t)))
                (finish
                 (save-excursion
                   (let ((fin (re-search-forward reorder-enders nil t)))
                     (if fin (1- fin)
                       (point-max))))))
            (with-silent-modifications
              (add-text-properties start finish
                                   '(font-lock-face
                                     confusingly-reordered
                                     face confusingly-reordered
                                     mouse-face highlight
                                     help-echo "\
This text is reordered on display in a way that could change its semantics;
use \\[forward-char] and \\[backward-char] to see the actual order of characters.")))
            (goto-char finish)
            (setq count (1+ count))))
        (message
         (if (> count 0)
             (ngettext
              "Highlighted %d confusingly-reordered text string"
              "Highlighted %d confusingly-reordered text strings"
              count)
           "No confusingly-reordered text strings were found")
         count)))))