进程参数欺骗原理

前置

参数欺骗或者说参数伪造这个功能以前也有简单写过但是当时并没有详细的写原理,只简单介绍了一下然后用代码写了一个参数欺骗Demon

之前的文章(Demon不在这个文章里在我github上)

首先我们要明白进程是如何获得参数的,写一个最简单的打印参数的程序

int main(int argc, char* argv[])
{
	printf("%s \n",argv[0]);
	system("pause");
}

这个大家应该都用过,在main函数里面通过argv获取进程参数,但是你有想过argv是怎么来的吗,它又是谁赋的值

有过win32开发经验搞过crt的或者稍微了解逆向的,应该知道main函数并不是程序真正的入口点,一般情况程序的入口点是mainCRTStartup,main函数则是在mainCRTStartup初始完成CRT环境后被调用的,而在CRT初始化过程中会调用GetCommandLine函数,这个函数返回一个指针,这个指针指向进程命令行缓冲区

函数原型

WINBASEAPI
LPSTR
WINAPI
GetCommandLineA(
    VOID
    );

WINBASEAPI
LPWSTR
WINAPI
GetCommandLineW(
    VOID
    );

一些下面会用到的结构体提前先列出来

TEB

_NT_TEB

PEB

分析

继续我们来分析一下GetCommandLineW的实现

可以看到GetCommandLineW是直接从一个地址中读取的值然后给eax,我们跟进查看是谁给此地址赋值的

双击进入
在这里就可以很清楚的看到是从PEB里取的值

如果你不明白为什么esi指向PEB可以去函数开头看一下esi是从哪里来的,基本就能明白

现在我们应该清楚进程参数该从哪里获取(PEB.ProcessParameters.CommandLine)

所以我们可以很简单的通过修改PEB达到目的 1.以暂停标志创建进程 2.修改PEB.ProcessParameters.CommandLine 3.继续运行进程

从上面也可以看出来CommandLine是一个UNICODE_STRING结构体

而GetCommandLine根据我们上面分析的结果,它并不解析其中的Length,单单返回Buffer。这就造成了一些问题,进程本身初始化获取参数时不会理会Length,但是部分进程管理工具会通过读取PEB寻找参数,然后依据UNICODE_STRING.Length去读取参数的长度,所以我们还可以利用这点欺骗进程管理工具

没更新参数前
开始写入
CE转到对应的进程地址可以看到原先的参数
写入完成后已经被更改了
这里故意破坏Length凡是依靠Length读取字符串的都会被截断
ProcessHacker读取时按照Length长度读取,导致被截断
最后弹出calc

代码

这块基本上算是对以前的一个补充想起来就写上了

最后更新于

这有帮助吗?