0x00 简介
Vim(Vi IMproved)是一款强大的文本编辑器。它支持多种编辑模式,具有丰富的编辑功能和高度可定制性。Vim 提供了代码折叠、语法高亮、自动补全等功能,适用于程序员和文本编辑爱好者。通过个性化配置和插件系统,用户可以定制快捷键、颜色方案等。Vim 还可以作为图形化编辑器,在不同操作系统上运行,并与版本控制系统集成。总之,Vim 是一款高效、灵活的编辑器,为用户提供优秀的编辑体验。
-
0x00 简介
-
0x01 Vim 配置加载过程
-
1. vim 配置说明
-
2. 确定已加载的配置
-
3. 系统级配置文件解析
-
4. 用户配置文件解析
-
5. 用户层ex编辑器配置文件
-
6. 默认配置文件
-
7. 自动加载的配置文件
-
8. vim 配置加载过程初步总结
-
-
0x02 Vim 配置加载细节问题
-
1. 系统配置与用户配置
-
2. 用户配置与默认配置文件
-
3. 用户配置与用户配置
-
4. runtimepath 与 $VIMRUNTIME
-
5. 哪些目录自动加载
-
6. 哪些文件自动加载
-
7. 自动加载好奇的知识点
-
-
0x03 vim 后门说明
-
0x04 vim 自身文件后门
-
1. 查找 vim 命令程序位置
-
2. 制作后门文件
-
-
0x05 配置文件后门
-
1. 执行系统命令
-
2. 屏蔽控制台输出
-
3. 规避 vim 阻塞
-
-
0x06 features
-
1. +libcall
-
2. +packages
-
3. +python3
-
4. +user_commands
-
5. +vim9script
-
-
0x07 总结
-
0x08 往期文章
0x01 Vim 配置加载过程
vim 配置加载过程简单描述就是先加载系统级别配置,之后加载个人用户配置,接下来以 Ubuntu 22.04 为例
可以通过 vim --version
来进行查看各种文件的位置以及一些系统包含的插件
vim --version
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
defaults file: "$VIMRUNTIME/defaults.vim"
fall-back for $VIM: "/usr/share/vim"
1. vim 配置说明
-
系统级别配置文件
$VIM/vimrc
-
用户配置文件
$HOME/.vimrc
-
次优先级用户配置文件
~/.vim/vimrc
-
用户层ex编辑器配置文件
$HOME/.exrc
-
默认配置文件
$VIMRUNTIME/defaults.vim
-
次默认配置文件
/usr/share/vim
其中 $VIM
是 vim 内置的变量而不是 Linux 的环境变量,当然 vim 也是可以使用 Linux 环境变量的
通过在vim的底线命令模式中 echo $变量名
来获取 vim 的配置文件地址
因此,在 Ubuntu Server 22.04 vim 默认配置为
-
系统级别配置文件
$VIM/vimrc
——>/usr/share/vim/vimrc -> /etc/vim/vimrc
-
用户配置文件
$HOME/.vimrc
——>~/.vimrc
-
次优先级用户配置文件
~/.vim/vimrc
-
用户层ex编辑器配置文件
$HOME/.exrc
——>~/.exrc
-
默认配置文件
$VIMRUNTIME/defaults.vim
——>/usr/share/vim/vim82/defaults.vim
-
$VIM
后备配置文件/usr/share/vim
这些配置文件默认情况下并不是都存在
2. 确定已加载的配置
但是这些配置文件中可能还会引用其他配置文件,因此想要了解本次vim 请求加载了哪些配置文件可以通过在vim的底线命令模式中输入 scriptnames
Ubuntu Server 22.04 默认情况下是没有 ~/.vim
目录的
首先加载的是系统级配置文件 /usr/share/vim/vimrc
, 之后根据系统级配置文件的内容加载了一些配置文件内容,默认没有发现用户级配置文件的加载
可以看到默认并没有用户配置
3. 系统级配置文件解析
vim 配置文件有自己的一套 vim 脚本语法,具体可以通过下面的链接进行学习
https://devhints.io/vimscript
https://www.w3cschool.cn/vim/
其中 "
是注释符号, runtime! xxx.vim
表示强制重新加载 xxx.vim
/usr/share/vim/vimrc
-> /etc/vim/vimrc
" All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by
" the call to :runtime you can find below. If you wish to change any of those
" settings, you should do it in this file (/etc/vim/vimrc), since debian.vim
" will be overwritten everytime an upgrade of the vim packages is performed.
" It is recommended to make changes after sourcing debian.vim since it alters
" the value of the 'compatible' option.
runtime! debian.vim
" Vim will load $VIMRUNTIME/defaults.vim if the user does not have a vimrc.
" This happens after /etc/vim/vimrc(.local) are loaded, so it will override
" any settings in these files.
" If you don't want that to happen, uncomment the below line to prevent
" defaults.vim from being loaded.
" let g:skip_defaults_vim = 1
" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible
" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
if has("syntax")
syntax on
endif
" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
"set background=dark
" Uncomment the following to have Vim jump to the last position when
" reopening a file
"au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
"filetype plugin indent on
" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd " Show (partial) command in status line.
"set showmatch " Show matching brackets.
"set ignorecase " Do case insensitive matching
"set smartcase " Do smart case matching
"set incsearch " Incremental search
"set autowrite " Automatically save before commands like :next and :make
"set hidden " Hide buffers when they are abandoned
"set mouse=a " Enable mouse usage (all modes)
" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
source /etc/vim/vimrc.local
endif
去掉注释后
runtime! debian.vim
if has("syntax")
syntax on
endif
if filereadable("/etc/vim/vimrc.local")
source /etc/vim/vimrc.local
endif
分为三部分
runtime! debian.vim 强制重新加载 debian.vim
经过测试,这里 debian.vim
所在路径为 $VIMRUNTIME
的值(/usr/share/vim/vim82
)的目录下
经过测试,这里直接写绝对路径是不行的,必须是这个目录的相对路径
if has("syntax")
syntax on
endif
这段代码检查当前 vim 是否支持语法高亮,如果支持则打开语法高亮
if filereadable("/etc/vim/vimrc.local")
source /etc/vim/vimrc.local
endif
这段配置代码的意思是,如果文件/etc/vim/vimrc.local
存在并且可读,则加载该文件
通过对系统级配置文件 /etc/vim/vimrc 进行分析,可以知道这个文件默认内容不多,主要就是开启语法高亮、重新加载配置文件 debian.vim 、引入 /etc/vim/vimrc.local
因此接下来分析 debian.vim 和 /etc/vim/vimrc.local
/usr/share/vim/vim82/debian.vim
这一看就是 debian 系操作系统特有的文件, Centos 以及 Rocky Linux 等没有这个文件,甚至系统级配置文件位置都不同
根据 /etc/vim/vimrc
中注释描述,将所有系统侧配置文件都放置在 /usr/share/vim/vim82/debian.vim
文件中,每次程序升级时,都有可能覆盖更新 /usr/share/vim/vim82/debian.vim
文件,因此一些个性化配置尽量在个人用户配置处进行
" Normally we use vim-extensions. If you want true vi-compatibility
" remove change the following statements
set nocompatible " Use Vim defaults instead of 100% vi compatibility
set backspace=indent,eol,start " more powerful backspacing
" Now we set some defaults for the editor
set history=50 " keep 50 lines of command line history
set ruler " show the cursor position all the time
" modelines have historically been a source of security/resource
" vulnerabilities -- disable by default, even when 'nocompatible' is set
set nomodeline
" Suffixes that get lower priority when doing tab completion for filenames.
" These are files we are not likely to want to edit or read.
set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc
" We know xterm-debian is a color terminal
if &term =~ "xterm-debian" || &term =~ "xterm-xfree86"
set t_Co=16
set t_Sf=[3%dm
set t_Sb=[4%dm
endif
" Some Debian-specific things
if has('gui')
" Must define this within the :if so it does not cause problems with
" vim-tiny (which does not have +eval)
function! <SID>MapExists(name, modes)
for mode in split(a:modes, '\zs')
if !empty(maparg(a:name, mode))
return 1
endif
endfor
return 0
endfunction
" Make shift-insert work like in Xterm
autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "nvso") | execute "map <S-Insert> <MiddleMouse>" | endif
autocmd GUIEnter * if !<SID>MapExists("<S-Insert>", "ic") | execute "map! <S-Insert> <MiddleMouse>" | endif
endif
" Set paper size from /etc/papersize if available (Debian-specific)
if filereadable("/etc/papersize")
let s:papersize = matchstr(readfile('/etc/papersize', '', 1), '\p*')
if strlen(s:papersize)
exe "set printoptions+=paper:" . s:papersize
endif
endif
这个配置文件中未包含对其他配置文件的引用
/etc/vim/vimrc.local
Ubuntu Server 22.04 中默认不存在这个文件
4. 用户配置文件解析
-
~/.vimrc
-
~/.vim/vimrc
Ubuntu 默认不存在vim个人用户配置文件
5. 用户层ex编辑器配置文件
~/.exrc
Ubuntu Server 22.04 默认不存在该配置文件
6. 默认配置文件
默认配置文件在没有个人用户的配置文件时使用,Ubuntu Server 22.04 默认无个人默认配置文件,因此默认情况下会启用默认配置文件
$VIMRUNTIME/defaults.vim
——> /usr/share/vim/vim82/defaults.vim
" The default vimrc file.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last change: 2021 Nov 17
"
" This is loaded if no vimrc file was found.
" Except when Vim is run with "-u NONE" or "-C".
" Individual settings can be reverted with ":set option&".
" Other commands can be reverted as mentioned below.
" When started as "evim", evim.vim will already have done these settings.
if v:progname =~? "evim"
finish
endif
" Bail out if something that ran earlier, e.g. a system wide vimrc, does not
" want Vim to use these default values.
if exists('skip_defaults_vim')
finish
endif
" Use Vim settings, rather than Vi settings (much better!).
" This must be first, because it changes other options as a side effect.
" Avoid side effects when it was already reset.
if &compatible
set nocompatible
endif
" When the +eval feature is missing, the set command above will be skipped.
" Use a trick to reset compatible only when the +eval feature is missing.
silent! while 0
set nocompatible
silent! endwhile
" Allow backspacing over everything in insert mode.
set backspace=indent,eol,start
set history=200 " keep 200 lines of command line history
set ruler " show the cursor position all the time
set showcmd " display incomplete commands
set wildmenu " display completion matches in a status line
set ttimeout " time out for key codes
set ttimeoutlen=100 " wait up to 100ms after Esc for special key
" Show @@@ in the last line if it is truncated.
set display=truncate
" Show a few lines of context around the cursor. Note that this makes the
" text scroll if you mouse-click near the start or end of the window.
set scrolloff=5
" Do incremental searching when it's possible to timeout.
if has('reltime')
set incsearch
endif
" Do not recognize octal numbers for Ctrl-A and Ctrl-X, most users find it
" confusing.
set nrformats-=octal
" For Win32 GUI: remove 't' flag from 'guioptions': no tearoff menu entries.
if has('win32')
set guioptions-=t
endif
" Don't use Ex mode, use Q for formatting.
" Revert with ":unmap Q".
map Q gq
" CTRL-U in insert mode deletes a lot. Use CTRL-G u to first break undo,
" so that you can undo CTRL-U after inserting a line break.
" Revert with ":iunmap <C-U>".
inoremap <C-U> <C-G>u<C-U>
" Only do this part when Vim was compiled with the +eval feature.
if 1
" Enable file type detection.
" Use the default filetype settings, so that mail gets 'tw' set to 72,
" 'cindent' is on in C files, etc.
" Also load indent files, to automatically do language-dependent indenting.
" Revert with ":filetype off".
filetype plugin indent on
" Put these in an autocmd group, so that you can revert them with:
" ":augroup vimStartup | exe 'au!' | augroup END"
augroup vimStartup
au!
" When editing a file, always jump to the last known cursor position.
" Don't do it when the position is invalid, when inside an event handler
" (happens when dropping a file on gvim) and for a commit message (it's
" likely a different one than last time).
autocmd BufReadPost *
\ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
\ | exe "normal! g`\""
\ | endif
augroup END
" Quite a few people accidentally type "q:" instead of ":q" and get confused
" by the command line window. Give a hint about how to get out.
" If you don't like this you can put this in your vimrc:
" ":augroup vimHints | exe 'au!' | augroup END"
augroup vimHints
au!
autocmd CmdwinEnter *
\ echohl Todo |
\ echo 'You discovered the command-line window! You can close it with ":q".' |
\ echohl None
augroup END
endif
" Switch syntax highlighting on when the terminal has colors or when using the
" GUI (which always has colors).
if &t_Co > 2 || has("gui_running")
" Revert with ":syntax off".
syntax on
" I like highlighting strings inside C comments.
" Revert with ":unlet c_comment_strings".
let c_comment_strings=1
endif
" Convenient command to see the difference between the current buffer and the
" file it was loaded from, thus the changes you made.
" Only define it when not defined already.
" Revert with: ":delcommand DiffOrig".
if !exists(":DiffOrig")
command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ | diffthis
\ | wincmd p | diffthis
endif
if has('langmap') && exists('+langremap')
" Prevent that the langmap option applies to characters that result from a
" mapping. If set (default), this may break plugins (but it's backward
" compatible).
set nolangremap
endif
在该配置文件中,也没有发现引入其他配置文件
7. 自动加载的配置文件
通过我们对各种 vim 官方的各种配置文件进行分析,但是并没有发现图中的 /usr/share/vim/vim82/syntax/syntax.vim
以及下面一系列的配置文件的加载部分,也就是说除了配置文件以外,还有其他部分决定着加载一些配置文件
通过一些学习,我发现 vim 会自动加载 runtimepath
这个项(options
) 值指向的目录中的部分目录下的配置文件,这段话有点绕,下面举例子
-
查看 runtimepath 的值
底线命令模式下
set runtimepath?
可以看到,Ubuntu 默认的 vim runtimepath 的值为
runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfi les/after,/etc/vim/after,/var/lib/vim/addons/after,~/.vim/after
-
测试其中一个目录中新建
plugin
目录并放置1.vim
配置文件以
/var/lib/vim/addons
目录为例默认情况是不启用行号的,接下来尝试在
/var/lib/vim/addons
目录新建plugin
目录,并在其中创建1.vim
配置文件,配置文件中写入set number
来让 vim 显示行号配置成功生效
8. vim 配置加载过程初步总结
通过一些探索,默认情况下 vim 会加载如下配置文件
系统级别配置文件
$VIM/vimrc
用户配置文件
$HOME/.vimrc
次优先级用户配置文件
~/.vim/vimrc
用户层ex编辑器配置文件
$HOME/.exrc
默认配置文件
$VIMRUNTIME/defaults.vim
runtimepath
项的值所指向的路径内部分内容
0x02 Vim 配置加载细节问题
1. 系统配置与用户配置
1) 相同的配置项以谁为准
一般软件来说,遇到相同配置项,最终都是以用户配置为准,我们通过一个实验来测试 vim 是如何做的
实验思路:
-
通过在系统配置
/etc/vim/vimrc
中配置set background=dark
, -
用户配置
~/.vimrc
中配置set background=light
-
测试最终vim背景颜色来判断最终结果
默认背景颜色为 dark
系统配置背景颜色为 dark
系统配置背景颜色为 dark
用户配置背景颜色为白色
现在打开 1.txt
查看背景颜色
配置最终以用户配置为准,但是似乎背景颜色没有改成白色,难道是 ssh 连接的原因吗?通过图形化界面测试也是一样,推测可能是 Ubuntu 的终端或vim不支持设置背景颜色
通过 background 项的值可知,系统配置与用户配置遇到相同值的情况下,以用户配置为主
现在我们加了用户配置,我们看一下详细的配置加载情况
可以看到, ~/.vimrc
是在 /usr/share/vim/vimrc
后加载的,也就是说可能是遇到相同配置项以后加载的配置文件为准,我们尝试在 /var/lib/vim/addons/plugin/1.vim
中添加 set background=dark
因此得出结论:vim 的配置文件在配置项相同的时候,以后加载的配置文件的结果为准
与常规软件的配置文件规则一样
其实在 vim 中可以在底线命令模式下输入 verbose set background?
来查看 background
这个项的值是来自哪个配置文件
2) 被覆盖的配置项会执行吗
上一个实验中被覆盖的 background
配置项,在未被覆盖前,系统配置文件中是否生效了呢?
肯定是生效过对吧,但是最为一个相对严谨的安全研究员,我们还是通过实验来验证一下
先科普 vim 配置文件中设置变量和打印变量的方法
设置变量
let g:my_variable = 'Hello, World!'
打印变量
echo g:my_variable
实验思路:
-
在系统配置文件中设置变量
flag
变量值为system
-
在用户配置文件中打印
flag
变量 -
在用户配置文件中设置
flag
变量值为user
-
在
/var/lib/vim/addons/plugin/1.vim
中打印flag
变量
现在尝试通过 vim 编辑 1.txt
可以看出,虽然最终 flag
变量的值被修改了,但是系统配置中设置 flag
变量这个操作是成功了的,相信看到这里,部分小伙伴已经对后门有想法了,但请不要着急,这部分主要是探索 vim 配置详细加载情况
2. 用户配置与默认配置文件
1) 用户配置文件存在且不为空
在 /etc/vim/vimrc
中曾有介绍,如果不存在用户配置文件,将启用默认配置文件 $VIMRUNTIME/defaults.vim
,如果存在用户配置文件,则不启动,实际情况是这样的吗?我们需要进行一个实验
实验思路
-
创建用户配置文件
~/.vimrc
-
删除
/var/lib/vim/addons/plugin/1.vim
以及plugin
文件夹 -
在默认配置文件中写入
set number
-
编辑
1.txt
查看结果
可以看到,存在用户配置文件的情况下,确实默认配置文件不会执行
如果用户配置文件是 ~/.vim/vimrc
也这样吗
用户配置文件 ~/.vim/vimrc
也是生效的
2) 用户配置文件存在且为空
如果用户配置文件存在,但是内容是空的,这种情况下默认配置文件会生效吗
可以看出,默认配置文件判断的是文件存不存在,而不是有没有内容
3) 用户配置文件不存在
如果用户配置文件不存在,默认文件就会执行吗
果然,在用户配置文件不存在的情况下,默认配置会生效
4) .vim 文件夹存在,用户配置文件不存在
看来默认配置文件检查的是具体的文件而不是目录
5) .vim/plugin/1.vim 存在,用户配置文件不存在
两个配置文件都执行了
3. 用户配置与用户配置
用户主配置文件也有两个文件 ~/.vimrc
和 ~/.vim/vimrc
,用户配置文件其他内容都在 ~/.vim/
目录下
Ubuntu 22.04 默认情况没有用户配置文件 ~/.vim/*
和 ~/.vimrc
1) 两个用户配置同时存在
如果 ~/.vimrc
或 ~/.vim/vimrc
只存在一个,则会自动执行,当两个文件同时存在会怎么样呢?
实验思路:
-
~/.vimrc
设置变量flag
的值为 0 -
~/.vim/vimrc
设置变量flag
的值为 1 -
echo 变量
flag
当两个用户配置文件同时存在时,默认会启用 ~/.vimrc
2) ~/.vimrc
存在, .vim/plugin
目录下配置文件是否执行
.vim/plugin
目录下的文件加载不受用户配置文件影响
4. runtimepath 与 $VIMRUNTIME
runtimepath
是一个配置项,而 $VIMRUNTIME
是一个vim自有的环境变量,每次启动 vim 时会将 $VIMRUNTIME
的值更新到 runtimepath
配置项中
1) 在 vim 中临时修改 $VIMRUNTIME 的值,会直接修改 runtimepath
吗
可以得出结论,在运行的 vim 中临时修改 $VIMRUNTIME
环境变量的值并不会影响 runtimepath
项的值
2) 永久修改 $VIMRUNTIME 的值,会修改 runtimepath
吗
看来似乎通过用户配置永久修改 $VIMRUNTIME
不会对 runtimepath
造成影响,尝试通过系统配置文件永久修改 $VIMRUNTIME
可以看到,启动vim会报错,找不到 /tmp/syntax/syntax.vim
,这说明设置生效了,我们回车继续
可以看到, runtimepath
的值并未受到影响,因此似乎 runtimepath
的值并不来自于 $VIMRUNTIME
但是看很多文章中都写的是 runtimepath
的值由多部分组成,其中一部分是 $VIMRUNTIME
,为什么我们修改了会失败呢?
此时我突然想起了修改后启动 vim 的报错,难道是修改后由于 /tmp
目录下缺少相关文件导致的?
实验证明一下
首先是执行 vim 不再报错了
结果还是一样的
有趣的是,在加载配置文件列表中,确实有几个配置文件是从 /tmp/vim_runtime
目录加载的,而 debian.vim
竟然没有从 /tmp/vim_runtime
之前我们讲过, debian.vim
的路径是从 $VIMRUNTIME
获取的,而强制重新加载 debian.vim
的配置文件的指令就在系统配置文件/etc/vim/vimrc
之中,如果这种脚前脚后的关系都无济于事的话,那后面的配置文件不使用我们修改过后的地址的配置文件也是可以理解的了
继续实验,在 /etc/vim/vimrc
中设置一下打印的选项,分别打印 $VIMRUNTIME
和 runtimepath
的值
从这个结果可以看出,在加载第一个配置文件/etc/vim/vimrc
之前, runtimepath
就已经存在了,因此我们在 /etc/vim/vimrc
中修改 $VIMRUNTIME
的值后也不会重新生成 runtimepath
但是重新加载 debian.vim
是在设置 $VIMRUNTIME
之后,为何 debian.vim
不使用我们修改后的$VIMRUNTIME
的值就很难让人理解了
既然我们修改了 $VIMRUNTIME
之后,有几个配置文件还是跟着改了目录的,因此我们尝试在 /etc/vim/vimrc
中使用 runtime! xxx.vim
来加载它们,看看这回是什么路径
这就说明 runtime!
命令加载的地址根本就不是当前$VIMRUNTIME
既然从加载第一个配置文件前,runtimepath
和 $VIMRUNTIME
就已经设置好了,要么是 vim 还有其他的配置文件,要么是 vim 直接从系统获取的配置
删除掉刚刚配置 $VIMRUNTIME
的内容,采用 Linux 环境变量的方式进行配置
果然,$VIMRUNTIME
是从 Linux 操作系统的环境变量来的
因此永久修改 $VIMRUNTIME
不一定会修改 runtimepath
,只有通过Linux 操作系统环境变量来永久修改 $VIMRUNTIME
时才会修改 runtimepath
的值,通过vim系统配置文件的方式永久修改 $VIMRUNTIME
不会修改 runtimepath
的值
3) runtimepath 是否可以通过环境变量设置
可以看到并没有什么影响,因此 runtimepath
的值并不是来自于 Linux 操作系统环境变量
4) runtimepath 是否可以通过配置文件修改
从结果可以看出,实际上 runtime! xxx.vim
引用的配置文件地址并不是由 $VINRUNTIME
来决定的,而是由 runtimepath
来决定的,这里官方应该是写错了,只不过由于 runtimepath
默认是由 $VIMRUNTIME
组成的,所以错得不是很明显
而 defaults.vim
是实打实的 $VIMRUNTIME
5. 哪些目录自动加载
$VIMRUNTIME 和 ~/.vim 目录下的部分目录中的脚本会在vim启动或运行过程中加载,具体目录如下
-
autoload
目录:包含自动加载的脚本文件 -
colors
目录:包含颜色主题文件 -
compiler
目录:包含编译器配置文件 -
doc
目录:包含文档文件 -
ftplugin
目录:包含文件类型相关的插件脚本 -
indent
目录:包含文件类型相关的缩进脚本 -
keymap
目录:包含键盘映射脚本 -
lang
目录:包含语言相关的文件 -
plugin
目录:包含插件脚本文件 -
syntax
目录:包含语法高亮脚本文件 -
ftdetect
目录:包含文件类型检测脚本 -
after
目录:包含 Vim 启动后加载的配置文件
1) autoload
如果大家看过《程序员的自我修养》、看过我写的《学完ELF后人间清醒的总结v1.0》或者了解过ELF文件结构与加载过程,大家肯定会了解一个概念 —— 延迟绑定
其实 autoload 的思想也是一样,对于需要程序启动时加载的插件就启动时加载,刚启动时用不到后期用到的插件就什么时候用,什么时候加载
这些启动 vim 过程中用不到的插件就放在 autoload 目录下,以自动函数的形式存放
自动函数也是一种函数,不过有一个固定的规范,autoload 下的文件名与函数名部分内容必须一致,举个例子
自动函数文件:/usr/share/vim/vim82/autoload/demo.vim
自动函数的定义
function! demo#MyFunction()
set number
endfunction
这个函数名字由 demo
#
MyFunction
组成,其中 deno
必须与文件名 demo
相同,#
是固定格式,具体函数名自定义就好
自动函数的加载
可以在 vim 的底线命令模式下直接输入 :call demo#MyFunction()
进行加载
当然,也可以通过写入到配置文件的方式加载
2) colors
colors 文件夹是 vim 的配色方案存储的文件夹,除非使用插件管理器(例如 vim-plug
) ,不然不会自动加载,可以通过 colorscheme mycolorscheme
来加载 colors/mycolorscheme.vim
这个颜色配置文件,举例如下:
Vim颜色配置文件: /usr/share/vim/vim82/colors/color_demo.vim
在 /etc/vim/vimrc
中添加 colorscheme color_demo
测试效果
成功加载配置文件
3) compiler
compiler 是与编译器相关的配置文件夹,当用户在底线命令模式中使用:compiler xxx
的时候,会自动加载compiler
目录下同名的配置文件
在 compiler
目录下已有的 gcc.vim
中添加 set number
打开 vim 测试效果
成功加载我们加入的配置
如果希望在vim打开某个类型的文件时,就加载相关类型对应的编译器配置文件,可以通过在 /etc/vim/vimrc
进行相关配置
以打开 go
类型文件时,自动切换 go
编译器,之后加载 /usr/share/vim/vim82/compiler/go.vim
为例
先通过 vim 打开 1.go
文件,查看未进行相关设置前效果
在 /usr/share/vim/vim82/compiler/go.vim
中添加 set number
接下来一步很重要
在 /etc/vim/vimrc
中添加 autocmd FileType go compiler go
打开 1.go
进行测试
如果你还不满足,希望在 vim 启动的时候就自动加载 compiler
目录下的某个配置文件,除了直接引用的方式以外,可以利用 VimEnter
事件通过在 /etc/vim/vimrc
中添加 autocmd VimEnter * compiler gcc
,实现打开任意类型文件时都加载 gcc
编译器,进而加载 gcc.vim
配置文件
在 /usr/share/vim/vim82/compiler/gcc.vim
中添加 set number
在 /etc/vim/vimrc
中添加 autocmd VimEnter * compiler gcc
打开 1.go
测试效果
打开 1.txt
测试效果
直接启动vim测试效果
成功加载我们的配置文件
4) doc
这个目录下的文件都是帮助文档,并不会自动加载,通常用户在底线命令模式下输入 :help xxx
就会显示出来了
5) ftplugin
ftplugin
目录用于存放与文件类型相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供相关的设置和命令。
这回以 python 类型文件为例
在 /usr/share/vim/vim82/ftplugin/python.vim
中添加 set number
打开 1.txt
进行测试
打开 1.py
进行测试
如果我们想为后缀名为 .pwd
的文件进行相关配置,直接在 ftplugin
目录下放置一个 pwd.vim
就可以吗?
打开 1.pwd
查看效果
看来没有那么简单,需要额外进行配置
需要在 /etc/vim/vimrc
中添加如下配置
autocmd BufNewFile,BufRead *.pwd setfiletype pwd
打开 1.txt
进行测试
打开 1.pwd
进行测试
成功实现在打开自定义类型文件时执行自定义的配置文件
6) indent
indent
目录用于存放与缩进相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供自定义的缩进设置
这回以 rust
文件为例
在 /usr/share/vim/vim82/indent/rust.vim
中添加 set number
打开 1.txt
测试效果
打开 1.rs
测试效果
成功加载相关配置文件
和上面相同,如果想要自定义一个 .pwd
类型文件的缩进配置,如何操作呢?
其实文件类型配置这些东西主要都是记录在一个文件中 /usr/share/vim/vim82/filetype.vim
,但是我们在这里不着急讨论,放在后面部分,我们参考其中的书写方法,在 /etc/vim/vimrc
文件中进行配置
au BufNewFile,BufRead *.rs setf rust
在 /etc/vim/vimrc
中添加下面的内容
au BufNewFile,BufRead *.pwd setf pwd
在 indent
文件夹内添加 pwd.vim
打开 1.txt
和 1.go
测试效果
打开 1.pwd
文件测试效果
成功加载自定义的配置文件
7) keymap
keymap
目录用于存放与键位映射相关的配置文件。这些文件可以根据文件类型自动加载,并为特定类型的文件提供自定义的键位映射
vim 默认的键位映射文件并不多,常见的 Python、Go 等都没有,正好我们为 .pwd
新建一个键位映射文件
看来还是需要在 /etc/vim/vimrc
中添加对 .pwd
后缀文件的解析结果配置
au BufNewFile,BufRead *.pwd setf pwd
打开 1.txt
测试效果
打开 1.pwd
测试效果
成功加载自定义的配置文件
8) lang
lang
目录用于存放与语言相关的配置文件。这些文件默认不会自动加载,一般在使用vim 部分多语言支持的插件时才会加载,当然,我们可以使用上面的 vim 事件来让其加载,这种加载方式适合于任何目录的配置文件
在 lang
目录中新建 zh_CN_18030.vim
文件
在 /etc/vim/vimrc
中。写入如下内容
autocmd VimEnter * source $VIMRUNTIME/lang/zh_CN_18030.vim
现在打开任意文件,测试效果
成功加载自定义的配置文件
这种加载方式适用于任何目录的文件,因此并非lang目录独有,经过测试, source
加载的语法文件后缀并不一定需要是 .vim
,其他后缀也是可以的
9) plugin
plugin
目录用于存放插件文件,这些插件文件可以添加新的功能、命令、映射键位等
这个目录太清爽了,不用配置,直接将配置文件放在里面就会在vim启动时自动加载,加载顺利是按照字母顺序来进行的
这个目录默认存在的文件不多,我们新建一个,在新建之前,我们先看一下打开 1.txt
的效果
在 plugin
文件夹新建 toxml.vim
打开 1.txt
测试效果
成功加载自定义配置文件
10) syntax
syntax
目录中的语法文件用于提供代码高亮和语法解析的功能。这些语法文件通常会在打开相应类型的文件时自动加载。
默认打开 1.pwd
vim打开未匹配到文件类型的文件时,会自动加载 /usr/share/vim/vim82/syntax/nosyntax.vim
在 /usr/share/vim/vim82/syntax/nosyntax.vim
中添加 set number
再次打开 1.pwd
删除 /usr/share/vim/vim82/syntax/nosyntax.vim
中的 set number
接下来我们通过新增文件类型来实现自动加载
在 /etc/vim/vimrc
中新增以下内容
au BufNewFile,BufRead *.pwd setf pwd
打开 1.pwd
成功加载自定义配置
11) ftdetect
ftdetect
目录用于自动检测文件类型,这个目录和plugin目录一样,目录下的配置文件可以自动加载
Ubuntu 22.04 中默认已经没有这个目录了,但是新建这个目录并在其中放置配置文件仍然有效
打开 1.txt
新建 ftdetect
目录并在其中创建 ttt.vim
成功加载自定义配置文件
12) macros
macros
目录用于存放宏文件,它们包含一系列 Vim 命令和操作的序列,macros
目录没有自动加载的特殊机制
13) pack
pack
目录用于管理插件和脚本包。当你将插件或脚本包放置在 pack
目录中时,Vim 会自动加载这些包
关于 pack 目录,网络上文件较少,先存的部分文章绝大多数也都是错误的,通过
:help packages
获取到了正确的使用方法
package 和 plugin 略有不同,package 可以包含多个插件,因此 pack 目录也有自己固定的格式
-
在 pack 目录创建包文件夹 ——
mypackage
-
在
mypackage
中创建固定名称的文件夹start
-
在
start
文件夹中创建任意名称文件夹,以pack1
为例 -
在
pack1
文件夹中创建固定名称文件夹plugin
或syntax
等 -
在
plugin
或syntax
中创建任意名称的 vim 配置文件pack_test.vim
-
在
pack_test.vim
中写入set number
未设置前打开 1.txt
创建 package 并写入内容
打开 1.txt
成功加载了自定义配置文件
14) print
print
目录是 Vim 默认的打印支持脚本所在的位置,并不是用于自动加载脚本的目录
15) spell
spell
目录下的拼写检查文件可以通过自动加载来启用拼写检查功能,暂未发现可以自动启动的方法
16) tutor
tutor
目录下的教程文件是通过自动加载来启用 Vim 自带的教程功能的,暂未发现可以自动启动的方法
17) after
after
目录是 Vim 中一个特殊的目录,用于存放在 Vim 启动后加载的配置文件。after
目录中的配置文件可以用于覆盖默认的 Vim 配置,以及在 Vim 启动后进行进一步的个性化设置
Ubuntu 22.04 默认情况下没有 after
文件夹,我们可以新建该文件夹
after
目录既然是用来覆盖默认的 vim 配置,就有和默认配置文件夹相同的目录结构,也就是说 after
目录下的 plugin
目录中的配置文件也会自动执行
打开 1.txt
发现并没有执行
删除 after 目录,在用户配置文件中创建 after 目录,按照上面的方式进行测试
再次打开 1.txt
也就是说 在Ubuntu 22.04上after目录只在用户配置中有效,在系统级配置中无效
18) 自动加载的目录小结
目录名 | 自动加载 | 修改配置文件的方式加载 | 打开特定格式文件自动加载 | 未发现自动加载 |
---|---|---|---|---|
autoload | 1 | |||
colors | 1 | |||
compiler | 1 | |||
doc | 1 | |||
ftplugin | 1 | |||
indent | 1 | |||
keymap | 1 | |||
lang | 1 | |||
plugin | 1 | |||
syntax | 1 | |||
ftdetect | 1 | |||
macros | 1 | |||
pack | 1 | |||
1 | ||||
spell | 1 | |||
tutor | 1 | |||
after | 1 |
6. 哪些文件自动加载
$VIMRUNTIME 和 ~/.vim 目录下的部分脚本会在vim启动或运行过程中加载
经过上个小节的洗礼,大家应该已经轻车熟路了,想要确定具体加载了哪些脚本,只需要分别打开有文件类型的文件、未知文件类型的文件、直接执行 vim
,之后分别在底线命令模式下执行 :scriptnames
就可以看到默认加载的脚本了
使用 vim 打开 1.go
文件脚本的加载情况
使用 vim 打开 a
文件的脚本加载情况
直接执行 vim
通过对比,可以得出,自动加载的脚本如下(第8条和第12条根据打开文件类型而定)
-
vimrc
-
debian.vim
在
vimrc
中默认引用 -
syntax/syntax.vim
-
syntax/synload.vim
-
syntax/syncolor.vim
-
colors/lists/default.vim
-
filetype.vim
-
scripts.vim
-
`defaults.vim
-
ftplugin.vim
-
indent.vim
-
syntax/nosyntax.vim
在目标文件未识别到文件类型或文件类型不需要语法高亮时自动加载
-
plugin/*
自动加载的文件小结
文件名 | 文件作用 | 是否自动加载 |
---|---|---|
vimrc | Vim 的全局配置文件,用于设置全局的 Vim 选项和自定义命令。它在 Vim 启动时自动加载,并为所有用户生效 | 是 |
debian.vim | 为 Debian 系统定制的 Vim 配置文件,包含了一些特定于 Debian 的配置选项和设置 | Debian等系统自动加载 |
syntax/syntax.vim | Vim 用于语法高亮显示的核心文件,定义了语法高亮的规则和逻辑 | 是 |
syntax/synload.vim | Vim 用于语法高亮显示的辅助文件,用于加载和管理语法文件 | 是 |
syntax/syncolor.vim | Vim 用于语法高亮显示的辅助文件,用于加载和管理语法文件 | 是 |
colors/lists/default.vim | Vim 颜色方案的默认配置文件,定义了默认的颜色方案 | 是 |
filetype.vim | 这个文件定义了文件类型的检测规则和相关设置,用于根据文件类型自动加载相应的配置和插件 | 是 |
scripts.vim | 这个文件包含一些 Vim 脚本的帮助函数和设置,用于支持 Vim 脚本的运行和调试 | 打开部分文件自动加载 |
defaults.vim | 默认的 Vim 配置选项,用于设置 Vim 的默认行为和外观 | 是 |
ftplugin.vim | 这个文件包含了一些文件类型相关的插件设置,用于为特定文件类型自动加载相应的插件和配置 | 打开部分文件自动加载 |
indent.vim | 这个文件包含了一些自动缩进的设置,用于根据文件类型自动设置正确的缩进规则 | 是 |
syntax/nosyntax.vim | Vim 用于禁用语法高亮显示的设置文件,用于取消对当前文件的语法高亮显示 | 未匹配到文件格式 或不需要语法高亮时自动加载 |
plugin/* | 各种插件 | 是 |
7. 自动加载好奇的知识点
runtime 和runtime!加载规则一致,对于之前已经被加载过的配置文件效果有些差异,因此在以下文章中讨论加载规则时不必纠结 runtime 还是runtime!,涉及到差异时,我会详细标注
1) $VIMRUNTIME 和 ~/.vim 效果是否一致
除了加载顺序以及after 目录差异外,未发现其他区别
2) runtime!
加载目录取决于什么
默认情况 /etc/vim/vimrc
中存在通过 runtime! debian.vim
的配置,在前面的部分中,我标注了 debian.vim
文件来自 $VIMRUNTIME
环境变量中,从结果看是没有错的
不过如果从原理来说,runtime!
加载配置文件的地址选择是来自于 runtimepath
项的,只不过前面也讲过 $VIMRUNTIME
的值是 runtimepath
的一部分
3) runtime!
存在多文件时如何选择
按照常规思路去想,一般来说是按照 runtimepath
的顺序,选择第一个找到相关文件的地址去重新加载,但是 vim 的思路似乎是 "小孩子才做选择,我全都要"
没错,runtime! xxx.vim
会将 runtimepath
指定的目录中所有找到的 xxx.vim
重新加载一遍
在 /etc/vim/vimrc
为例,添加 runtime! demo.vim
获取 runtimepath
的值
runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfiles/after,/etc/vim/after,/var/lib/vim/addons/after,~/.vim/after
按照先后顺序整理如下
-
~/.vim
-
/var/lib/vim/addons
-
/etc/vim
-
/usr/share/vim/vimfiles
-
/usr/share/vim/vim82
-
/usr/share/vim/vimfiles/after
-
/etc/vim/after
-
/var/lib/vim/addons/after
-
~/.vim/after
现在分别在 ~/.vim
、/var/lib/vim/addons
、/etc/vim/after
中放置 demo.vim
,内容均为打印当前文件所在位置
此时打开 vim
可以看到,我只在 /etc/vim/vimrc
中设置了一次 runtime! demo.vim
,runtimepath
制定的目录下所有的demo.vim
都重新加载了一遍,具体顺序是按照 runtimepath
中的顺序来的
4) runtime!
低权限可以引用高权限文件吗
我们直接将 3)
中 /etc/vim/vimrc
中的 runtime! demo.vim
移到 ~/.vimrc
或 ~/.vim/vimrc
中
可以看到,低权限配置 runtimepath
是可以加载高权限文件夹下的配置文件的
此时,如果用 sudo 来执行 vim ,就不会加载 demo.vim
了,毕竟sudo后执行vim的变成了 root,默认情况下 root 的 ~/.vimrc
和 ~/.vim/vimrc
,即使存在也不存在 runtime! demo.vim
指令
5) runtime!
可以加载非 *.vim
的文件吗
之前我们演示的都是加载 *.vim
文件,现在尝试加载非 .vim
后缀的文件
首先获取 runtimepath
runtimepath=~/.vim,/var/lib/vim/addons,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/vim82,/usr/share/vim/vimfiles/after,/etc/vim/a
fter,/var/lib/vim/addons/after,~/.vim/after
在 /usr/share/vim/vim82
目录下新建 demo.vim
,内容为 set number
![](../../../../Library/Application Support/typora-user-images/.png)
在 /etc/vim/vimrc
中使用 runtime! demo.vim
进行加载
打开 1.txt
配置生效,现在将 demo.vim
修改为 demo
,并将 /etc/vim/vimrc
中的内容一并修改
总结
本篇文章只是利用了 vim 部分功能来制作后门,案例也处于是概念性的,以系统命令执行为主。当然,如果你已经通篇读了本篇文章,相信你一定了解细节支持,有了很多思路,有时间可以在本地实现一下。
本篇文章较长,公众号阅读可能不是很方便,因此我们给大家准备了 PDF 版本
公众号:【吉吉说安全】,对我发消息【后门】获取PDF版本」
「如果你也想学习更多这类安全技术,【详情下方图片了解】,【扫下方二维码加入】:只做高质量优质精品内容」
「会持续给大家更新更好东西,期待得到你免费的」
免责声明
由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本公众号及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!