0x00 环境变量管理
环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。不同的操作系统和运行环境中对环境变量的管理方式都不同,本文通过抽象各操作系统中对环境变量的操作探索一种通过统一接口操作环境变量的方式。
每个环境变量的值是一个列表,列表中每个元素通过分割符分开。Unix 中使用 :
,Windows 中使用 ;
,例如最常用的 PATH
环境变量就是一个由多个路径组成的环境变量。
由于 Windows 中
:
被用作Qualifier
可能出现在路径中,例如:C:\
,所以不能使用:
作为分隔符。
环境变量的结构模式可以于 Redis 中的 List 数据结构做类比:
- 环境变量名对应
Key
- 环境变量值对应
List
- 环境变量值中的单个值对应
Element
统一接口的环境变量操作列表
方法 | 说明 |
---|---|
env_insert | 环境变量值头部加入一个元素 |
env_append | 环境变量值尾部加入一个元素 |
env_trim | 环境变量值中删除某一元素 |
env_amend | 修改环境变量 |
env_unset | 删除环境变量 |
env_list | 查询环境变量 |
0x01 Bash/Zsh 环境实现
类 Unix 中的环境变量没有持久化的概念,所有的环境变量作用域都只限制在当前的 Session 中,所有需要通过修改 .*rc
脚本的方式来模拟持久化。
##################################
# Environment Operate for Bash/Zsh
##################################
# add new element to environment variable insert mode
# $1 enviroment variable
# $2 new element
function env_insert()
{
eval local env_var=\$\{${1}\-\}
local new_element=${2%/}
if ! echo $env_var | grep -E -q "(^|:)$new_element($|:)"; then
eval export $1="${new_element}\${$1:+\:}\${$1-}"
fi
}
# add new element to environment variable append mode
# $1 enviroment variable
# $2 new element
function env_append()
{
eval local env_var=\$\{${1}\-\}
local new_element=${2%/}
if ! echo $env_var | grep -E -q "(^|:)$new_element($|:)"; then
eval export $1="\${$1-}\${$1:+\:}${new_element}"
fi
}
# trim element from environment variable
# $1 enviroment variable
# $2 trim element
function env_trim()
{
eval local env_var=\$\{${1}\-\}
local del_element=${2%/}
eval export $1="$(echo ${env_var} | sed -E -e "s;(^|:)${del_element}(:|\$);\1\2;g" -e "s;^:|:\$;;g" -e "s;::;:;g")"
}
# amend environment variable
# $1 enviroment variable
# $2 amend element
function env_amend()
{
eval export $1="$(echo $2)"
}
# unset environment variable
# $1 enviroment variable
function env_unset()
{
eval unset $1
}
# list element from environment variable
# $1 enviroment variable
function env_list()
{
eval local env_var=\$\{${1}\-\}
echo -e ${env_var//:/\\n}
}
0x02 PowerShell 环境实现
Windows 中环境变量有持久化的概念,对于持久化的环境变量常规的操作方式为:
- Run
sysdm.cpl
->Advanced
->Environment Variables
Powershell 中使用 .NET API 的 Environment
模块可以很方便的操作环境变量。
非持久化的环境变量存储在 Env:\
的 PSDrive 中,作为一种 Provider 的形式存在。
PowerShell 中可以通过指定 env_level
来决定需要操作的环境变量作用域
变量作用域 | 说明 |
---|---|
Process | 非持久化存储,作用于当前的 Session,相当于 Env:\ |
User | 持久化存储,作用于当前用户,相当于 HKCU:\Environment |
Machine | 持久化存储,作用于整个系统,相当于 HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment |
<####################################
# Environment Operate for PowerShell
####################################>
# ${env_level} possible values are { Prcess, User, Machine }
function internal_env_opration {
Param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$is_insert,
[Parameter(Mandatory = $true, Position = 1)] [string]$env_name,
[Parameter(Mandatory = $true, Position = 2)] [String]$env_value,
[Parameter(Mandatory = $false, Position = 3)] [String]$env_level = "Process"
)
if ($IsWindows -or $Env:OS) { $separator = ';' } else { $separator = ':' }
$curr_values = [Environment]::GetEnvironmentVariable($env_name, $env_level)
if ((-not $curr_values) -or ($curr_values -eq "")) {
[Environment]::SetEnvironmentVariable($env_name, $env_value, $env_level)
}
else {
if ($curr_values -like "*$separator*") {
$values_array = $curr_values.split("$separator")
foreach ($value in $values_array) {
if ($value -eq $env_value) {
return
}
}
}
else {
if ($curr_values -eq $env_value) {
return
}
}
if ($is_insert) {
[Environment]::SetEnvironmentVariable($env_name, "$env_value$separator$curr_values", $env_level)
}
else {
[Environment]::SetEnvironmentVariable($env_name, "$curr_values$separator$env_value", $env_level)
}
}
}
function env_insert {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $true, Position = 1)] [String]$env_value,
[Parameter(Mandatory = $false, Position = 2)] [String]$env_level = "Process"
)
internal_env_opration $true $env_name $env_value $env_level
}
function env_append {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $true, Position = 1)] [String]$env_value,
[Parameter(Mandatory = $false, Position = 2)] [String]$env_level = "Process"
)
internal_env_opration $false $env_name $env_value $env_level
}
function env_trim {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $true, Position = 1)] [String]$env_value,
[Parameter(Mandatory = $false, Position = 2)] [String]$env_level = "Process"
)
if ($IsWindows -or $Env:OS) { $separator = ';' } else { $separator = ':' }
$curr_values = [Environment]::GetEnvironmentVariable($env_name, $env_level)
if ((-not $curr_values) -or ($curr_values -eq "")) {
return
}
else {
if ($curr_values -like "*$separator*") {
$values_array = $curr_values.split("$separator")
foreach ($value in $values_array) {
if (-not ($value -eq $env_value)) {
if (-not $new_value) {
$new_value = "$value"
}
else {
$new_value += "$separator$value"
}
}
}
[Environment]::SetEnvironmentVariable($env_name, $new_value, $env_level)
}
else {
if ($curr_values -eq $env_value) {
[Environment]::SetEnvironmentVariable($env_name, $null, $env_level)
}
}
}
}
function env_amend {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $true, Position = 1)] [String]$env_value,
[Parameter(Mandatory = $false, Position = 2)] [String]$env_level = "Process"
)
[Environment]::SetEnvironmentVariable($env_name, $env_value, $env_level)
}
function env_unset {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $false, Position = 1)] [String]$env_level = "Process"
)
[Environment]::SetEnvironmentVariable($env_name, $null, $env_level)
}
function env_list {
Param (
[Parameter(Mandatory = $true, Position = 0)] [string]$env_name,
[Parameter(Mandatory = $false, Position = 1)] [String]$env_level = "Process"
)
if ($IsWindows -or $Env:OS) { $separator = ';' } else { $separator = ':' }
$curr_values = [Environment]::GetEnvironmentVariable($env_name, $env_level)
if (($curr_values) -and (-not $curr_values -eq "")) {
if ($curr_values -like "*$separator*") {
$values_array = $curr_values.split("$separator")
foreach ($value in $values_array) {
Write-Host "$value"
}
}
else {
Write-Host "$curr_values"
}
}
}