2014-07-15 47 views
1

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

代码:

#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

NtQueryInformationProcess()需要一个进程句柄,而不是一个PID。 – Elmue

回答

3

可惜GetCommandLineW没有在命令行中从PEB返回。在BaseDllInitialize例程中,复制是由PEB命令行结构构成的,从那时起,此副本由GetCommandLineW使用。你需要在内存中找到这个副本来修改它,这看起来相当困难,也很危险/不可靠。

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

+0

这也是我的结论,但你的答案是第一位的。谢谢。 – mll5

1

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