刘收获

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

获取,修改进程命令行

在XDebug的源码学习中看到的命令行操作,将主要源码摘录出来做了个获取和更改进程命令行的Demo.

0x01  获取命令行

     这里获取命令行的方式并不是通过调用GetCommandLine函数。

   而是借由ntdll中的NtQueryInformationProcess函数查询ProcessBasicInformation,得到ProcessBasicInformation中的PebBaseAddress字段。得到进程PEB地址后,再通过PEB地址的获取ProcessParameter字段地址,

     最后通过ProcessParameter字段获取到ProcessParameter的 CommandLine  字段,得到了命令行的存储地址。

主要源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void* GetPEBLocation(HANDLE hProcess)
{
    ULONG RequiredLen = 0;
    void* PebAddress = 0;
    PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
 
    if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == STATUS_SUCCESS)
    {
        PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
    }
    else
    {
        if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == STATUS_SUCCESS)
        {
            PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
        }
    }
 
    return PebAddress;
}
 
 
BOOL Getcommandlineaddr(duint *CommandLineAddressdr)
{
    duint PEBAddress;
    duint pprocess_parameters;
    duint ProcessParametersAddress;
    duint ReturnLength;
    PEBAddress = (duint)GetPEBLocation(__ProcessHandle);
    ProcessParametersAddress = (duint) & (((PPEB)PEBAddress)->ProcessParameters);
 
 
 
    ReadProcessMemory(__ProcessHandle, reinterpret_cast<LPVOID>(ProcessParametersAddress), &pprocess_parameters,
        sizeof(pprocess_parameters), reinterpret_cast<SIZE_T*>(&ReturnLength));
 
    *CommandLineAddressdr = (duint) & (((RTL_USER_PROCESS_PARAMETERS*)pprocess_parameters)->CommandLine);
 
    return TRUE;
}

  

 

0x02  修改命令行

    修改命令行的关键就是操作内存。

    XDebug首先获取GetCommandLineA或GetCommandLineW函数的地址。

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
if (!valfromstring("kernelBase:GetCommandLineA", &getcommandline))
    {
        if (!valfromstring("kernel32:GetCommandLineA", &getcommandline))
        {
             
            return FALSE;
        }
    }
 
 
bool valfromstring(const char* string, duint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly, bool allowassign)
{
    duint result;
    if (!Calculate(string, result, false /*valuesignedcalc()*/, allowassign, silent, baseonly, value_size, isvar, hexonly))
        return false;
    *value = result;
    return true;
}
 
bool Calculate(const char* string, duint & value, bool signedcalc, bool allowassign, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
{
     
    return DoEvaluate(string, value, silent, baseonly, value_size, isvar, hexonly);
}
bool DoEvaluate(const char* string, duint & result, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
{
    return valfromstring_noexpr(string, (duint*)&result, silent, baseonly, value_size, isvar, hexonly);
}
bool valfromstring_noexpr(const char* string, duint* value, bool silent, bool baseonly, int* value_size, bool* isvar, bool* hexonly)
{
    if (!value || !string || !*string)
        return false;
 
    if (valapifromstring(string, value, value_size, true, silent, hexonly)) //then come APIs
        return true;
    return false;
}
bool valapifromstring(const char* name, duint* value, int* value_size, bool printall, bool silent, bool* hexonly)
{
    //explicit API handling
    const char* apiname = strchr(name, ':'); //the ':' character cannot be in a path: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
    bool noexports = false;
    if (!apiname) //not found
    {
        apiname = strstr(name, "..") ? strchr(name, '.') : strrchr(name, '.'); //kernel32.GetProcAddress support
        if (!apiname) //not found
        {
            apiname = strchr(name, '?'); //the '?' character cannot be in a path either
            noexports = true;
        }
    }
    if (apiname)
    {
        char modname[MAX_MODULE_SIZE] = "";
        strncpy_s(modname, name, _TRUNCATE);
        modname[apiname - name] = 0;
        apiname++;
        if (!strlen(apiname))
            return false;
        duint modbase = 0;//ModBaseFromName(modname);从MAP表里查基地址
        char szModPath[MAX_PATH] = "kernel32.dll";
        if (!1/*ModPathFromAddr(modbase, szModPath, _countof(szModPath))*/)//查表得到完整路径
        {
            //if (!silent)
                //dprintf(QT_TRANSLATE_NOOP("DBG", "Could not get filename of module %p\n"), modbase);
        }
        else
        {
            HMODULE mod = LoadLibraryExW(Utf8ToUtf16(szModPath).c_str(), 0, DONT_RESOLVE_DLL_REFERENCES);
            if (!mod)
            {
                //if (!silent)
                //  dprintf(QT_TRANSLATE_NOOP("DBG", "Unable to load library %s\n"), szModPath);
            }
            else
            {
                duint addr = noexports ? 0 : SafeGetProcAddress(mod, apiname);
                //if (addr) //found exported function
                //  addr = modbase + (addr - (duint)mod); //correct for loaded base
                //else //not found
                {
                }
                FreeLibrary(mod);
                if (addr) //found!
                {
                    if (value_size)
                        *value_size = sizeof(duint);
                    if (hexonly)
                        *hexonly = true;
                    *value = addr;
                    return true;
                }
            }
        }
        return false;
    }
    return true;
}

  获取到这个所谓的“函数地址后并没有结束,这里需要设计到重定向表的重定向问题,在这个地址的基础上还需要两次跳转才能得到真正的功能函数地址。这个地址上的第一次跳转,是跳向重定向表,然后重定向表再给出地址,跳向库中真正的功能函数地址。

  对应的源码操作(图中getcommandline即为前文valfromstring函数获取的GetCommandLineA或GetCommandLineW函数的地址。)

 

 

调试反汇编查看获取到的getcommandline地址:

 

越过FF 25两字节,获取到跳转地址76b311fch:

1
ReadProcessMemory(__ProcessHandle, reinterpret_cast<LPVOID>(getcommandline + 2), data, 100, reinterpret_cast<SIZE_T*>(&ReturnLength));

  

 

 

内存窗口查看76b311fch:处内容,得到重定向表给出的功能函数地址:0x7406e210

 

 

 

1
ReadProcessMemory(__ProcessHandle, reinterpret_cast<LPVOID>(*(int*)data), data, 100, reinterpret_cast<SIZE_T*>(&ReturnLength));

  

 

反汇编窗口中查看0x7406e210中的内容:

 

 

现在就可以通过字符串匹配来得到命令行的存储地址:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
 
    750FE9CA | A1 CC DB 1A 75           | mov eax,dword ptr ds:[751ADBCC]         |
 
    750FE9CF | C3                       | ret                                     |
 
    */
 
    if (data[0] != 0xA1 || data[5] != 0xC3)
 
    {
 
         return FALSE;
 
    }
 
    command_line_stored = *((duint*)& data[1]);

  

找到地址后最后一步写入地址:

1
2
3
WriteProcessMemory(__ProcessHandle, reinterpret_cast<LPVOID>(command_line_stored), &new_command_line, sizeof(new_command_line), reinterpret_cast<SIZE_T*>(&ReturnLength));
 
    //update the pointer in the debuggee

  

 

posted on   沉疴  阅读(2181)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示