我正在尝试修改可执行文件的命令行参数,以便GetCommandLine()将返回我设置的字符串。由于我想在任何人之前修改命令行值,我已经通过/ ENTRY开关将我的入口点更改为testme()函数,并且还设置了/ NODEFAULTLIB选项以排除CRT。使用以下代码,为什么我可以通过CommandLine更改字符串缓冲区指针但不能分配全新的缓冲区?
代码:
#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"x y\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 "a b", not "x y".
wchar_t *pCmdLine = GetCommandLine();
return 0;
}
答案 0 :(得分:4)
不幸的是GetCommandLineW
没有从PEB返回命令行。在BaseDllInitialize
例程中,复制由PEB命令行结构组成,从那时起GetCommandLineW
使用此副本。您需要在内存中找到此副本才能对其进行修改,这似乎非常困难且危险/不可靠。
您可以查看像Detours这样的API挂钩,但更简单的解决方案可能就是首先使用您想要的命令行启动您的可执行文件。如果命令行是正确的,你可以测试它何时启动,如果没有,它可以使用所需的命令行生成另一个自身副本。
答案 1 :(得分:2)
经过一些试验和错误后,我想出了以下内容。我写了一个C可执行文件,只与kernel32.lib
链接,但没有链接CRT
。在exe
中,我EAT
修补了GetCommandLineX
中的kernel32.dll
个功能。然后我加载另一个我的DLL(test.dll),它需要GetCommandLineX
方法作为其功能的一部分。由于kernel32
被修补,因此加载器使用修补的函数指针填充test.dll的导入表。最后,test.dll中的方法调用了我的GetCommandLineX版本,我可以轻松地更改它们的实现。