
Linux在启动一个进程时,系统会在/proc下创建一个以PID命名的文件夹,在该文件夹下会有我们的进程的信息
这些信息,有的是软链接,有的是文本,有的是目录
查看这些信息需要对应的权限
其中部分常用信息如下
cwd 符号链接, 是进程运行目录 sudo ls -al /proc/PID/cwd
exe 符号连接, 是执行程序的绝对路径 sudo ls -al /proc/PID/exe
cmdline 文本, 是程序运行时输入的命令行命令 sudo cat /proc/PID/cmdline
environ 文本, 记录了进程运行时的环境变量 sudo cat /proc/PID/environ
fd 目录, 里面是进程打开或使用的文件的符号连接 sudo ls -al /proc/PID/fd
方法都是想出来的,介绍一种,可以把要在启动时运行的放在一个单独的Servlet的init()方法中 在webxml中配置这个servlet的load-on-startup 属性值大于等于0就行了,如果小于0或不设置则是在访问此servlet时才加载至于设置为几如果要优先其他执行那就设置的低些,相反就设置高些程序启动时会根据load-on-startup的值由低到高顺序加载
线程注入,说到底还是创建线程,只不过创建的线程在别的进程中运行而已,那么,我们需要下手的地方跟监控普通线程创建需要下手的地方应当是一样的——NtCreateThread(不过这不是一个太好的选择,因为NtCreateThread的定位稍显麻烦。这儿只是一个为了说明如何监控而做一个例子而已,所以尽可能选择简单的方法来挂钩,修改ssdt可以挂这个函数,所以就选择了它。^-^更好的选择见后文)。
我认为我有必要先列出NtCreateThread的原型:
NTSTATUS
NtCreateThread(
__out PHANDLE ThreadHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
__in HANDLE ProcessHandle,
__out PCLIENT_ID ClientId,
__in PCONTEXT ThreadContext,
__in PINITIAL_TEB InitialTeb,
__in BOOLEAN CreateSuspended
)
__out的那些就都不解释了,主要解释需要用到的。
access_mask是访问权限,不解释;ObjectAttr是对象属性,_opt的,不解释;ProcessHandle就是将要被创建线程的进程(新线程在这个进程中运行)的句柄了;剩下几个也跟本文无关,也不解释,需要了解详细信息可以查MSDN。
需要关注的参数我想我已经说的很明确了——ProcessHandle。我们可以使用ObReferenceObjectByHandle来获取这个Handle所指向的进程的EPROCESS的地址(PEPROCESS)。
剩下的就是判断这个线程是正常创建还是远程创建的问题了,这个判断将会变得很容易,因为我们可以用获得到PEPROCESS和IoGetCurrentProcess的结果相比较——NtCreateThread总是应当在创建者的进程上下文中被执行。
不过当我们编译运行之后就会发现,还有一个问题是我们不得不关注的——运行程序的时候父进程会“帮助”子进程创建子进程的主要线程(因为这个时候子进程还没有线程,所以不可能自己创建),所以这就引出了另外一个问题——如何判断这个远程线程创建是注入还是正常的程序运行呢?
简单分析下我们不难发现,二者的区别在于将被创建线程的进程是否还存在其他线程——因为我们的代码是在NtCreateThread之前执行的,所以如果是正常运行的程序的话,这个时候它不应当有任何的线程,而线程注入则不同,线程注入的话目标进程应当已经有了至少一个线程(一个主线程和若干个附属线程(或者没有附属线程))。
那么如何判断目标进程是否已经存在线程呢?在EPROCESS结构中:
+0x190 ThreadListHead : _LIST_ENTRY
我想这个ThreadListHead这是很容易理解的。。。。
实现方法(因为只是为了演示,所以所有的地址、偏移等都是硬编码):
ThreadListHead = 0x190;
//==========================================
BOOLEAN
ProcessNoThread( PEPROCESS Process)
{
PLIST_ENTRY Entry;
PLIST_ENTRY ThreadListEntry;
PLIST_ENTRY ListHead;
ThreadListEntry = (PLIST_ENTRY)((ULONG)Process + ThreadListHead);
Entry = ThreadListEntry->Flink;
return (Entry==ThreadListEntry);
}
//==========================================
NTSTATUS new_NtCreateThread(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PVOID InitialTeb,
IN BOOLEAN CreateSuspended )
{
NTSTATUS st;
PVOID pepCurrentProcess=0;
st=ObReferenceObjectByHandle(ProcessHandle,(ACCESS_MASK)PROCESS_ALL_ACCESS,NULL,KernelMode,&pepCurrentProcess,NULL);
if (NT_SUCCESS(st))
{
if (IoGetCurrentProcess()!=pepCurrentProcess)
{
if (!ProcessNoThread((PEPROCESS)pepCurrentProcess)) DbgPrint("PROCESS 0x%X have created a thread into PROCESS 0x%X, NtCreateThread return value = 0x%x",IoGetCurrentProcess(),pepCurrentProcess,st);
}
ObDereferenceObject((PVOID)pepCurrentProcess);
}
st=old_NtCreateThread(ThreadHandle,DesiredAccess,ObjectAttributes,ProcessHandle,ClientId,ThreadContext,InitialTeb,CreateSuspended);
return st;
}
//==========================================
我想这段代码也不至于太难理解。。
是时候说说其他的一些问题了:
1、其实hook PspCreateThread要比hook NtCreateThread相对容易一些(两个函数同样都没有被导出,而PspCreateThread可以很容易的在PsCreateSystemThread中被定位,但NtCreateThread的定位就需要分析PE文件了(改SSDT另当别论,不过改SSDT的强度太差))。
2、遍历进程的线程是使用硬编码的,这使得通用性变得很差,而通过遍历PspCidTable枚举系统中的线程则成为一种不错的方法(从PspCreateThread中的代码来看,是由PspCreateThread在PspCidTable中ExCreateHandle的,但是我没有做测试)
就这样把,我自负的认为我的语言表达能力还算是不错的。
---EOF---
任务管理器里面,把ppid一栏打开,就看到了。
ppid就是父进程的进程号在windows下查看某个运行程序(或进程)的命令行参数使用下面的命令。
wmicprocessgetcaption,commandline/value如果想查询某一个进程的命令行参数,使用下列方式。
wmicprocesswherecaption=”svchostexe”getcaption,commandline/value这样就可以得到进程的可执行文件位置等信息。
以上就是关于Linux查看进程运行的完整路径及参数的方法全部的内容,包括:Linux查看进程运行的完整路径及参数的方法、javaWeb程序启动时怎么获取或设置系统参数、HOOK NtCreateThread 怎么获得 创建进程的命令行参数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)