如果修改或添加环境变量,则必须重新启动命令提示符。是否有一个命令,我可以执行,将这样做而不重新启动CMD?
当前回答
可以通过在指定进程本身中覆盖环境表来实现这一点。
作为概念的证明,我写了这个示例应用程序,它只是在cmd.exe进程中编辑一个(已知的)环境变量:
typedef DWORD (__stdcall *NtQueryInformationProcessPtr)(HANDLE, DWORD, PVOID, ULONG, PULONG);
int __cdecl main(int argc, char* argv[])
{
HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");
int processId = atoi(argv[1]);
printf("Target PID: %u\n", processId);
// open the process with read+write access
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, processId);
if(hProcess == NULL)
{
printf("Error opening process (%u)\n", GetLastError());
return 0;
}
// find the location of the PEB
PROCESS_BASIC_INFORMATION pbi = {0};
NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
if(status != 0)
{
printf("Error ProcessBasicInformation (0x%8X)\n", status);
}
printf("PEB: %p\n", pbi.PebBaseAddress);
// find the process parameters
char *processParamsOffset = (char*)pbi.PebBaseAddress + 0x20; // hard coded offset for x64 apps
char *processParameters = NULL;
if(ReadProcessMemory(hProcess, processParamsOffset, &processParameters, sizeof(processParameters), NULL))
{
printf("UserProcessParameters: %p\n", processParameters);
}
else
{
printf("Error ReadProcessMemory (%u)\n", GetLastError());
}
// find the address to the environment table
char *environmentOffset = processParameters + 0x80; // hard coded offset for x64 apps
char *environment = NULL;
ReadProcessMemory(hProcess, environmentOffset, &environment, sizeof(environment), NULL);
printf("environment: %p\n", environment);
// copy the environment table into our own memory for scanning
wchar_t *localEnvBlock = new wchar_t[64*1024];
ReadProcessMemory(hProcess, environment, localEnvBlock, sizeof(wchar_t)*64*1024, NULL);
// find the variable to edit
wchar_t *found = NULL;
wchar_t *varOffset = localEnvBlock;
while(varOffset < localEnvBlock + 64*1024)
{
if(varOffset[0] == '\0')
{
// we reached the end
break;
}
if(wcsncmp(varOffset, L"ENVTEST=", 8) == 0)
{
found = varOffset;
break;
}
varOffset += wcslen(varOffset)+1;
}
// check to see if we found one
if(found)
{
size_t offset = (found - localEnvBlock) * sizeof(wchar_t);
printf("Offset: %Iu\n", offset);
// write a new version (if the size of the value changes then we have to rewrite the entire block)
if(!WriteProcessMemory(hProcess, environment + offset, L"ENVTEST=def", 12*sizeof(wchar_t), NULL))
{
printf("Error WriteProcessMemory (%u)\n", GetLastError());
}
}
// cleanup
delete[] localEnvBlock;
CloseHandle(hProcess);
return 0;
}
样例输出:
>set ENVTEST=abc
>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528
>set ENVTEST
ENVTEST=def
笔记
这种方法也仅限于安全限制。如果目标在更高的海拔或更高的帐户(如SYSTEM)上运行,那么我们将没有权限编辑它的内存。
如果你想对一个32位的应用程序这样做,上面的硬编码偏移量将分别更改为0x10和0x48。这些偏移量可以通过在调试器中转储_PEB和_RTL_USER_PROCESS_PARAMETERS结构体来找到(例如在WinDbg dt _PEB和dt _RTL_USER_PROCESS_PARAMETERS中)
要将概念证明更改为OP需要的内容,只需枚举当前系统和用户环境变量(如@tsadok的答案所记录的那样),并将整个环境表写入目标进程的内存中。
Edit: The size of the environment block is also stored in the _RTL_USER_PROCESS_PARAMETERS struct, but the memory is allocated on the process' heap. So from an external process we wouldn't have the ability to resize it and make it larger. I played around with using VirtualAllocEx to allocate additional memory in the target process for the environment storage, and was able to set and read an entirely new table. Unfortunately any attempt to modify the environment from normal means will crash and burn as the address no longer points to the heap (it will crash in RtlSizeHeap).
其他回答
这适用于windows 7: SET PATH=%PATH%
通过输入echo %PATH%测试,它工作正常。也设置如果你打开一个新的cmd,不需要那些讨厌的重新启动:)
环境变量保存在HKEY_LOCAL_MACHINE\SYSTEM\ControlSet\Control\Session Manager\Environment中。
许多有用的环境变量,如Path,都存储为REG_SZ。有几种方法可以访问注册表,包括REGEDIT:
REGEDIT /E <“HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \会话管理器\ \控制环境”
输出从神奇的数字开始。因此,要用find命令搜索它,它需要输入并重定向:type <filename> | findstr -c:\"Path\"
所以,如果你只是想用系统属性刷新当前命令会话中的路径变量,下面的批处理脚本可以很好地工作:
RefreshPath.cmd:
@echo off REM This solution requests elevation in order to read from the registry. if exist %temp%\env.reg del %temp%\env.reg /q /f REGEDIT /E %temp%\env.reg "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment" if not exist %temp%\env.reg ( echo "Unable to write registry to temp location" exit 1 ) SETLOCAL EnableDelayedExpansion for /f "tokens=1,2* delims==" %%i in ('type %temp%\env.reg ^| findstr -c:\"Path\"=') do ( set upath=%%~j echo !upath:\\=\! >%temp%\newpath ) ENDLOCAL for /f "tokens=*" %%i in (%temp%\newpath) do set path=%%i
尝试以管理员身份打开一个新的命令提示符。我在Windows 10上使用了这个方法。(我知道这是一个老答案,但我不得不分享这个,因为不得不为这个写VBS脚本是荒谬的)。
我只是想说,那些使用Anaconda的人,当你使用chocoley Refreshenv命令时;所有与conda相关的环境变量都将丢失。 要解决这个问题,最好的方法是重新启动CMD。:(
我在批处理脚本中使用以下代码:
if not defined MY_ENV_VAR (
setx MY_ENV_VAR "VALUE" > nul
set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%
通过在SETX之后使用SET,可以直接使用“本地”变量,而无需重新启动命令窗口。在下次运行时,将使用环境变量。
推荐文章
- 我如何找到哪个程序正在使用端口80在Windows?
- 在Windows中有像GREP这样的模式匹配实用程序吗?
- 如何在Windows命令提示符下运行.sh ?
- Mac OS X中的环境变量
- 如何从命令行在windows中找到mysql数据目录
- 在没有事件源注册的情况下写入Windows应用程序事件日志
- 如何在Makefile中设置子进程的环境变量
- Windows FINDSTR命令的未记录的特性和限制是什么?
- 无法在Windows上从/usr/local/ssl/openssl.cnf加载配置信息
- GIT克隆在windows中跨本地文件系统回购
- 如何在POM.xml中引用环境变量?
- 如何运行一个PowerShell脚本而不显示窗口?
- PowerShell:仅为单个命令设置环境变量
- 为什么这个Windows批处理文件只执行第一行,而在命令shell中执行所有三行?
- 环境变量存储在Windows注册表的哪里?