0x00 前言
之前记录了
cmder Cmder.bat分析学习
DIY自己的cmder.exe
这两篇文章,接下来要做的事情就是分析cmder的启动部分。
0x01 正文
首先这里打开cmder的设置就会发现cmdre最先加载的就是这类,那么这里也就是我们的分析目标了
1.start语句分析分析
cmd /k ""%ConEmuDir%\..\init.bat""
这里的cmd /k的意思就是执行完命令不关闭窗口
ConEmuDir这里应该是获取到当前路径,然后执行init.bat这个命令。
这里我们进行一个自定义设置
然后重新启动
2.init.bat
这里对init.bat文件进行分析,这个文件已经上传到了github上。
链接
2.1 1~10行
@echo off
set CMDER_INIT_START=%time%
:: Init Script for cmd.exe
:: Created as part of cmder project
:: !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED
:: !!! Use "%CMDER_ROOT%\config\user_profile.cmd" to add your own startup commands
bat开头是一个@echo off
%time% 为获取当前的时间
照例写一个脚本:
脚本链接
@echo OFF
SET times=%time%
echo %times%
效果
注释我们就不理了
2.2 10~20行
set verbose_output=0
set debug_output=0
set time_init=0
set fast_init=0
set max_depth=1
set nix_tools=1
set "CMDER_USER_FLAGS= "
这里的内容就是设置一个初始变量,具体内容还要看接下来的分析。
2.3 20~30行
:: Find root dir
if not defined CMDER_ROOT (
if defined ConEmuDir (
for /f "delims=" %%i in ("%ConEmuDir%\..\..") do (
set "CMDER_ROOT=%%~fi"
)
) else (
for /f "delims=" %%i in ("%~dp0\..") do (
set "CMDER_ROOT=%%~fi"
)
)
)
if not defined CMDER_ROOT 这里defined的意思就是判断变量名是否存在
这里用小教本进行举例:
脚本链接
@echo OFF
set ceshi=1
if defined DEMO (
echo ok
) else (
echo no DEMO
)
if defined ceshi (
echo ok,ceshi
) else (
echo no ceshi
)
运行效果:
2.4 30~40
:: Remove trailing '\' from %CMDER_ROOT%
if "%CMDER_ROOT:~-1%" == "\" SET "CMDER_ROOT=%CMDER_ROOT:~0,-1%"
call "%cmder_root%\vendor\bin\cexec.cmd" /setpath
call "%cmder_root%\vendor\lib\lib_base"
call "%cmder_root%\vendor\lib\lib_path"
call "%cmder_root%\vendor\lib\lib_console"
call "%cmder_root%\vendor\lib\lib_git"
call "%cmder_root%\vendor\lib\lib_profile"
if “%CMDER_ROOT:~-1%” == “” SET “CMDER_ROOT=%CMDER_ROOT:~0,-1%” 这里就是去掉最后的\
call这里的就是和start一样的作用,就是调起其他的cmd。
这里就要分其他的文章来进行分析,所以此处暂停。
好了已经分析完这些调用的东西,给人的感觉实际上就是python的调用库啦
以下是分析链接
cmder Cmder.bat分析学习
DIY自己的cmder.exe
cmder init.bat分析学习
cmder lib_console.cmd分析学习
cmder lib_path.bat分析学习
cmder lib_base.bat分析学习
cmder lib_git.cmd分析学习
cmder lib_profile.cmd分析学习
2.5 var_loop
这里的这个var_loop就是一个设置项
2.5.1 第一部分
if "%~1" == "" (
goto :start
) else if /i "%1" == "/f" (
set fast_init=1
) else if /i "%1" == "/t" (
set time_init=1
) else if /i "%1"=="/v" (
set verbose_output=1
) else if /i "%1"=="/d" (
set debug_output=1
) else if /i "%1" == "/max_depth" (
if "%~2" geq "1" if "%~2" leq "5" (
set "max_depth=%~2"
shift
) else (
%lib_console% show_error "'/max_depth' requires a number between 1 and 5!"
exit /b
)
2.5.2 第二部分
else if /i "%1" == "/c" (
if exist "%~2" (
if not exist "%~2\bin" mkdir "%~2\bin"
set "cmder_user_bin=%~2\bin"
if not exist "%~2\config\profile.d" mkdir "%~2\config\profile.d"
set "cmder_user_config=%~2\config"
shift
)
) else if /i "%1" == "/user_aliases" (
if exist "%~2" (
set "user_aliases=%~2"
shift
)
) else if /i "%1" == "/git_install_root" (
if exist "%~2" (
set "GIT_INSTALL_ROOT=%~2"
shift
) else (
%lib_console% show_error "The Git install root folder "%~2", you specified does not exist!"
exit /b
)
2.5.3 第三部分
else if /i "%1"=="/nix_tools" (
if "%2" equ "0" (
REM Do not add *nix tools to path
set nix_tools=0
shift
) else if "%2" equ "1" (
REM Add *nix tools to end of path
set nix_tools=1
shift
) else if "%2" equ "2" (
REM Add *nix tools to front of path
set nix_tools=2
shift
)
) else if /i "%1" == "/home" (
if exist "%~2" (
set "HOME=%~2"
shift
) else (
%lib_console% show_error The home folder "%2", you specified does not exist!
exit /b
)
) else if /i "%1" == "/svn_ssh" (
set SVN_SSH=%2
shift
) else (
set "CMDER_USER_FLAGS=%1 %CMDER_USER_FLAGS%"
)
shift
goto var_loop
2.5.4 总结
这里实际上就是处理一些参数,通过shift进行左移然后通过goto进行循环设置。还是一个十分机制的方法。
2.6 start
2.6.1 第一部分
:: Sets CMDER_SHELL, CMDER_CLINK, CMDER_ALIASES
%lib_base% cmder_shell
%lib_console% debug_output init.bat "Env Var - CMDER_ROOT=%CMDER_ROOT%"
%lib_console% debug_output init.bat "Env Var - debug_output=%debug_output%"
if defined CMDER_USER_CONFIG (
%lib_console% debug_output init.bat "CMDER IS ALSO USING INDIVIDUAL USER CONFIG FROM '%CMDER_USER_CONFIG%'!"
)
:: Pick right version of clink
if "%PROCESSOR_ARCHITECTURE%"=="x86" (
set architecture=86
set architecture_bits=32
) else (
set architecture=64
set architecture_bits=64
)
2.6.2 第二部分
if "%CMDER_CLINK%" == "1" (
%lib_console% verbose_output "Injecting Clink!"
:: Run clink
if defined CMDER_USER_CONFIG (
if not exist "%CMDER_USER_CONFIG%\settings" (
echo Generating clink initial settings in "%CMDER_USER_CONFIG%\settings"
copy "%CMDER_ROOT%\vendor\clink_settings.default" "%CMDER_USER_CONFIG%\settings"
echo Additional *.lua files in "%CMDER_USER_CONFIG%" are loaded on startup.\
)
"%CMDER_ROOT%\vendor\clink\clink_x%architecture%.exe" inject --quiet --profile "%CMDER_USER_CONFIG%" --scripts "%CMDER_ROOT%\vendor" --nolog
) else (
if not exist "%CMDER_ROOT%\config\settings" (
echo Generating clink initial settings in "%CMDER_ROOT%\config\settings"
copy "%CMDER_ROOT%\vendor\clink_settings.default" "%CMDER_ROOT%\config\settings"
echo Additional *.lua files in "%CMDER_ROOT%\config" are loaded on startup.
)
"%CMDER_ROOT%\vendor\clink\clink_x%architecture%.exe" inject --quiet --profile "%CMDER_ROOT%\config" --scripts "%CMDER_ROOT%\vendor" --nolog
)
) else (
%lib_console% verbose_output "WARNING: Incompatible 'ComSpec/Shell' Detetected Skipping Clink Injection!"
)
这里可能还要对默认的clink的默认配置进行一个分析,这里可能要暂停一段时间。
分析完了,clink调用以及配置说明,接着往下看。
2.6.3 第三部分
set PLINK_PROTOCOL=ssh
if not defined TERM set TERM=cygwin
:: The idea:
:: * if the users points as to a specific git, use that
:: * test if a git is in path and if yes, use that
:: * last, use our vendored git
:: also check that we have a recent enough version of git by examining the version string
if defined GIT_INSTALL_ROOT (
if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" goto :SPECIFIED_GIT
) else if "%fast_init%" == "1" (
if exist "%CMDER_ROOT%\vendor\git-for-windows\cmd\git.exe" (
%lib_console% debug_output "Skipping Git Auto-Detect!"
goto :VENDORED_GIT
)
)
这里需要分析SPECIFIED_GIT和VENDORED_GIT
2.6.4 SPECIFIED_GIT
:SPECIFIED_GIT
%lib_console% debug_output "Using /GIT_INSTALL_ROOT from '%GIT_INSTALL_ROOT%..."
goto :CONFIGURE_GIT
这里可以看到跳转到了CONFIGURE_GIT
2.6.5 CONFIGURE_GIT
2.6.5.1 第一部分
:: Add git to the path
rem add the unix commands at the end to not shadow windows commands like more
if %nix_tools% equ 1 (
%lib_console% debug_output init.bat "Preferring Windows commands"
set "path_position=append"
) else (
%lib_console% debug_output init.bat "Preferring *nix commands"
set "path_position="
)
if exist "%GIT_INSTALL_ROOT%\cmd\git.exe" %lib_path% enhance_path "%GIT_INSTALL_ROOT%\cmd" %path_position%
if exist "%GIT_INSTALL_ROOT%\mingw32" (
%lib_path% enhance_path "%GIT_INSTALL_ROOT%\mingw32\bin" %path_position%
) else if exist "%GIT_INSTALL_ROOT%\mingw64" (
%lib_path% enhance_path "%GIT_INSTALL_ROOT%\mingw64\bin" %path_position%
)
if %nix_tools% geq 1 (
%lib_path% enhance_path "%GIT_INSTALL_ROOT%\usr\bin" %path_position%
)
2.6.5.2 第二部分
if not defined SVN_SSH set "SVN_SSH=%GIT_INSTALL_ROOT:\=\\%\\bin\\ssh.exe"
:: Find locale.exe: From the git install root, from the path, using the git installed env, or fallback using the env from the path.
:: 设置locale.exe
if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\locale.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\locale.exe"
if not defined git_locale for /F "delims=" %%F in ('where locale.exe 2^>nul') do (if not defined git_locale set git_locale="%%F")
if not defined git_locale if exist "%GIT_INSTALL_ROOT%\usr\bin\env.exe" set git_locale="%GIT_INSTALL_ROOT%\usr\bin\env.exe" /usr/bin/locale
if not defined git_locale set git_locale=env /usr/bin/locale
%lib_console% debug_output init.bat "Env Var - git_locale=%git_locale%"
if not defined LANG (
for /F "delims=" %%F in ('%git_locale% -uU 2') do (
set "LANG=%%F"
)
)
%lib_console% debug_output init.bat "Env Var - GIT_INSTALL_ROOT=%GIT_INSTALL_ROOT%"
%lib_console% debug_output init.bat "Found Git in: '%GIT_INSTALL_ROOT%'"
goto :PATH_ENHANCE
2.6.6 PATH_ENHANCE
%lib_path% enhance_path "%CMDER_ROOT%\vendor\bin"
%lib_path% enhance_path_recursive "%CMDER_ROOT%\bin" %max_depth%
if defined CMDER_USER_BIN (
%lib_path% enhance_path_recursive "%CMDER_USER_BIN%" %max_depth%
)
%lib_path% enhance_path "%CMDER_ROOT%" append
:: Drop *.bat and *.cmd files into "%CMDER_ROOT%\config\profile.d"
:: to run them at startup.
%lib_profile% run_profile_d "%CMDER_ROOT%\config\profile.d"
if defined CMDER_USER_CONFIG (
%lib_profile% run_profile_d "%CMDER_USER_CONFIG%\profile.d"
)
if not defined user_aliases (
if defined CMDER_USER_CONFIG (
set "user_aliases=%CMDER_USER_CONFIG%\user_aliases.cmd"
) else (
set "user_aliases=%CMDER_ROOT%\config\user_aliases.cmd"
)
)
if "%CMDER_ALIASES%" == "1" (
REM The aliases environment variable is used by alias.bat to id
REM the default file to store new aliases in.
if not defined aliases (
set "aliases=%user_aliases%"
)
REM Make sure we have a self-extracting user_aliases.cmd file
if not exist "%user_aliases%" (
echo Creating initial user_aliases store in "%user_aliases%"...
copy "%CMDER_ROOT%\vendor\user_aliases.cmd.default" "%user_aliases%"
) else (
%lib_base% update_legacy_aliases
)
:: Update old 'user_aliases' to new self executing 'user_aliases.cmd'
if exist "%CMDER_ROOT%\config\aliases" (
echo Updating old "%CMDER_ROOT%\config\aliases" to new format...
type "%CMDER_ROOT%\config\aliases" >> "%user_aliases%"
del "%CMDER_ROOT%\config\aliases"
) else if exist "%user_aliases%.old_format" (
echo Updating old "%user_aliases%" to new format...
type "%user_aliases%.old_format" >> "%user_aliases%"
del "%user_aliases%.old_format"
)
)
:: Add aliases to the environment
:: 运行user_aliases,这里可能又要暂停一段时间了。
call "%user_aliases%"
user_aliases分析完成。
继续向下看
if exist "%GIT_INSTALL_ROOT%\post-install.bat" (
echo Running Git for Windows one time Post Install....
pushd "%GIT_INSTALL_ROOT%\"
"%GIT_INSTALL_ROOT%\git-cmd.exe" --no-needs-console --no-cd --command=post-install.bat
popd
)
:: Set home path
if not defined HOME set "HOME=%USERPROFILE%"
%lib_console% debug_output init.bat "Env Var - HOME=%HOME%"
set "initialConfig=%CMDER_ROOT%\config\user_profile.cmd"
if exist "%CMDER_ROOT%\config\user_profile.cmd" (
REM Create this file and place your own command in there
%lib_console% debug_output init.bat "Calling - %CMDER_ROOT%\config\user_profile.cmd"
call "%CMDER_ROOT%\config\user_profile.cmd"
)
if defined CMDER_USER_CONFIG (
set "initialConfig=%CMDER_USER_CONFIG%\user_profile.cmd"
if exist "%CMDER_USER_CONFIG%\user_profile.cmd" (
REM Create this file and place your own command in there
%lib_console% debug_output init.bat "Calling - %CMDER_USER_CONFIG%\user_profile.cmd
call "%CMDER_USER_CONFIG%\user_profile.cmd"
)
)
if not exist "%initialConfig%" (
echo Creating user startup file: "%initialConfig%"
copy "%CMDER_ROOT%\vendor\user_profile.cmd.default" "%initialConfig%"
)
if "%CMDER_ALIASES%" == "1" if exist "%CMDER_ROOT%\bin\alias.bat" if exist "%CMDER_ROOT%\vendor\bin\alias.cmd" (
echo Cmder's 'alias' command has been moved into "%CMDER_ROOT%\vendor\bin\alias.cmd"
echo to get rid of this message either:
echo.
echo Delete the file "%CMDER_ROOT%\bin\alias.bat"
echo.
echo or
echo.
echo If you have customized it and want to continue using it instead of the included version
echo * Rename "%CMDER_ROOT%\bin\alias.bat" to "%CMDER_ROOT%\bin\alias.cmd".
echo * Search for 'user-aliases' and replace it with 'user_aliases'.
)
set initialConfig=
set CMDER_CONFIGURED=1
set CMDER_INIT_END=%time%
if %time_init% gtr 0 (
"%cmder_root%\vendor\bin\timer.cmd" %CMDER_INIT_START% %CMDER_INIT_END%
)
exit /b
0x02 结尾
init就这样分析完了。。。总感觉还有啥没有掌握到
好了,解密了,其实cmder还是在很大的基础上是基于ConEmu的,只是做了 一个配置。
环境变量是在这里配置的
然后aliases是在这里配置的
clink是在这里进行调起的
很多内容都是在对git进行设置,其实主要是为了配置一些内容。这些东西这里也是可以进行配置的。
总的来说emmm,cmder其实一点都不难,并且可自定义性还是非常强的,而且这里还有很多东西是在调试,还有一个非常直观的东西,这个bat和php十分相似,尤其是在变量的域控上。
就在此处结尾吧,剩下的就是自定义的过程了。