修改GetCommandLine()的命令行参数

我试图修改我的可执行文件的命令行参数,以便GetCommandLine()将返回我设置的string。 由于我想在任何人之前修改命令行值,我已经通过/ ENTRY开关将我的入口点改为testme()函数,并且还设置了/ NODEFAULTLIB选项以排除CRT。 使用下面的代码为什么我可以通过CommandLine更改string缓冲区指针,但不能分配一个全新的缓冲区?

代码:

#include <Windows.h> #include <winternl.h> typedef NTSTATUS (WINAPI *PFN_NtQueryInformationProcess)( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, IN PVOID ProcessInformation, IN ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength ); int testme() { // Get PEB block address PROCESS_BASIC_INFORMATION pbi; ULONG result; PFN_NtQueryInformationProcess pfnQueryProcess = (PFN_NtQueryInformationProcess) GetProcAddress(LoadLibrary("ntdll"), "NtQueryInformationProcess"); pfnQueryProcess(GetCurrentProcessId(), ProcessBasicInformation, &pbi, sizeof(pbi), &result); // Modify ProcessParameters->CommandLine // This works pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer[0] = L'a'; pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer[1] = L' '; pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer[2] = L'b'; pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer[3] = L'\0'; pbi.PebBaseAddress->ProcessParameters->CommandLine.Length = 6; // This does not work UNICODE_STRING cmdLine; wchar_t wszNewCmdLine[] = L"xy\0"; cmdLine.Buffer = (wchar_t*)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t)*pbi.PebBaseAddress->ProcessParameters->CommandLine.MaximumLength); cmdLine.MaximumLength = pbi.PebBaseAddress->ProcessParameters->CommandLine.MaximumLength; cmdLine.Length = sizeof(wszNewCmdLine) - sizeof(L'\0'); //Copy buffer for(int i=0; i<cmdLine.Length; ++i) cmdLine.Buffer[i] = wszNewCmdLine[i]; pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer = cmdLine.Buffer; pbi.PebBaseAddress->ProcessParameters->CommandLine.Length = cmdLine.Length; pbi.PebBaseAddress->ProcessParameters->CommandLine.MaximumLength = cmdLine.MaximumLength; // Now testing, pCmdLine returned is "ab", not "xy". wchar_t *pCmdLine = GetCommandLine(); return 0; } 

Solutions Collecting From Web of "修改GetCommandLine()的命令行参数"

不幸的是, GetCommandLineW不会从PEB返回命令行。 在BaseDllInitialize例程中,副本由PEB命令行结构构成,并且从此GetCommandLineW将使用此副本。 你需要在内存中找到这个副本来修改它,这似乎相当困难,也是危险/不可靠的。

你可以看看像Detours这样的API钩子,但是更简单的解决方案可能就是首先使用你想要的命令行启动你的可执行文件。 如果命令行是正确的,你可以测试它何时启动,如果没有,它会用所需的命令行产生自己的另一个副本。

经过一些试验和错误,我想出了以下内容。 我写了一个只能链接到kernel32.lib的C可执行文件,并没有链接CRT 。 在exe ,我在kernel32.dllGetCommandLineX函数进行EAT修补。 然后我加载另一个需要GetCommandLineX方法的dll(test.dll)作为其功能的一部分。 由于kernel32被打补丁,加载程序用补丁函数指针填充test.dll的导入表。 最后,test.dll中的方法调用我的GetCommandLineX版本,我可以轻松地更改它们的实现。