2014-07-15 46 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版本,我可以輕鬆更改它們的實現。