-
-
点滴记录--stubPE之procs
-
发表于: 2012-7-19 20:34 6206
-
上一次帖子记录了下stub_PE工具的导入表、导出表、资源表和重定位表等功能的简单实现,这一次看下Procs功能,其实就是个加强版的进程管理器。
尽管思路很简单,但在实现过程中对于我等C++新手而言还是有些操作上的难度的(只怪之前一直迷恋搞汇编),在这里就介绍下过程中遇到的问题和解决方法就当做个笔记,新手可以看个乐呵,老牛们请果断飘过~
不过其中有个亮点是该进程管理器可以结束系统中的关键进程,当然结束后会导致蓝屏
先上个图
xp下
Win7下
先贴下主要用到的函数(函数过多不一一列出,其他可以参考MSDN):
创建快照:
HANDLE WINAPI CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);
获取第一个进程
BOOL WINAPI Process32First(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
获取下一个进程
BOOL WINAPI Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
获取第一个模块
BOOL WINAPI Module32First(
HANDLE hSnapshot,
LPMODULEENTRY32 lpme
);
获取下一个模块
BOOL WINAPI Module32Next(
HANDLE hSnapshot,
LPMODULEENTRY32 lpme
);
获取程序图标资源
HICON ExtractIcon(
HINSTANCE hInst, // instance handle
LPCTSTR lpszExeFileName, // file name
UINT nIconIndex // icon index
);
打开进程令牌
BOOL OpenProcessToken(
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle
);
查询令牌权限
BOOL LookupPrivilegeValue(
LPCTSTR lpSystemName, // system name
LPCTSTR lpName, // privilege name
PLUID lpLuid // locally unique identifier
);
调整令牌权限
BOOL AdjustTokenPrivileges(
HANDLE TokenHandle, // handle to token
BOOL DisableAllPrivileges, // disabling option
PTOKEN_PRIVILEGES NewState, // privilege information
DWORD BufferLength, // size of buffer
PTOKEN_PRIVILEGES PreviousState, // original state buffer
PDWORD ReturnLength // required buffer size
);
大致思路挺简单,获取进程部分: 首先用函数CreateToolhelp32Snapshot创建进程快照(需要指定TH32CS_SNAPPROCESS)参数,再由返回的快照句柄用Process32First函数来获取第一个进程信息,保存在ROCESSENTRY32结构中,结构中有进程名称(不包括路径),进程ID,包含线程个数,包含模块ID等
如果Process32First返回成功就用Process32Next获取下一个进程信息,获取进程主要是这三个函数Process32Next能够自动获取下一个进程的信息直到返回值为FALSE,所以就可以通过判断Process32Next返回结果来循环获取进程信息;其实类似文件查找函数FindFile 和FindNextFile功能。都是根据前一个返回结果继续搜索,原理也很简单进程信息存储在系统内的链表当中,根据创建快照相当于指向了链表头指针,查找第一个后就可以沿着链表指针查找下一个数据位置,直到链表末尾。
获取进程的模块部分类似: 同样用CreateToolhelp32Snapshot创建模块快照当然需要用(TH32CS_SNAPPROCESS参数),有返回的快照句柄用Module32First获取第一个进程信息,保存在MODULEENTRY32结构中,这个结构内容稍复杂些包括模块基地址、模块大小、模块句柄、模块全路径名称、模块ID和进程ID等信息;如果Module32First返回成功就用Module32Next获取下一个模块信息,获取模块也主要是这三个函数。
问题和方法:
1.列表控件的一些使用方法
实现进程列表和模块列表需要用到List Control控件显示信息。如果控件有多列显示信息时,如果选择某行信息只会第一列被选中,其他列不被选中,
同时被选中方法是:添加列表控件风格为多列同时选中,用到宏为LVS_EX_FULLROWSELECT
如下:
m_ProcessList.SetExtendedStyle(m_ProcessList.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
m_ModuleList.SetExtendedStyle(m_ModuleList.GetExtendedStyle()|LVS_EX_FULLROWSELECT);
注:m_ProcessList,m_ModuleList为ClistCtrl控件对象分别代表进程控件和模块控件
2.外部函数使用类成员变量
为了保持进程刷新状态需要用定时器的回调函数来实时更新进程列表,而回调函数处理使需要用到类成员中的进程列表控件所关联的变量,例如回调函数中需要用到进程控件获取列表内容:CTaskMsgMFC::m_ProcessList.GetItemText();编译器会提示m_ProcessList为未定义的变量;
这个问题属于C++编程中常遇到的基本问题,如果外部函数需要使用类的成员变量,要求累的成员变量为static定义类型否则编译器会找不到变量而提示未定义的变量。
例如:
在类中定义该成员变量时用”static“关键字指定。
static CListCtrl m_ProcessList;
static CListCtrl m_ModuleList;
并且在调用文件中再次声明变量方式为:
变量类型 类名::变量名称
比如:
CListCtrl CTaskMsgMFC::m_ProcessList;
CListCtrl CTaskMsgMFC::m_ModuleList;
这样在使用时就可以正常引用,当然也可以不用这种方式而用另一种如:((CTaskMsgMFCDlg*)theApp.m_pMainWnd)->m_ProcessList.GetItemText();通过使用theApp指针来引用控件变量这种方式虽然可以,但对于我来说远没有上一种方式容易理解。
3.为进程控件列表添加程序图标时遇到的问题
(1)OpenProcess打开进程失败
为了完善些在控件中显示进程和模块信息时,最好显示进程和模块的图标,而显示进程图标时需要获取图标资源,方法多种可以用SHGetFileInfo函数,或者ExtractIcon函数(本程序中使用的后者)这两个函数都要用到程序全路径名称,而在获取进程信息时PROCESSENTRY32结构中进程名称并不包括函数路径,这样就需要我们用其他方法来获取全路径。一种方法是使用OpenProcess打开进程获得进程句柄,再由句柄作参数,用EnumProcessModules函数枚举进程模块,由进程句柄和模块句柄作参数用GetModuleFileNameEx函数获取进程全路径名称。但是在实践过程中打开进程并不一定成功,如果不成功就取不出全路径以至于取程序图标失败。这当然是无法忍受的。
解决办法是在打开进程前为进程提升权限,来确保打开进程成功:
以调整权限宏TOKEN_ADJUST_PRIVILEGES做函数OpenProcessToken的参数打开进程令牌,用查询权限LookupPrivilegeValue函数返回权限的LUID值填充TOKEN_PRIVILEGES结构作为函数AdjustTokenPrivileges的参数来实现提升权限。(具体代码请查看附件)
(2)为列表控件添加图标
方法
首先定义两个全局的CimageList类图形对象如:
//进程图标列表
CImageList ProcessImageList;
//模块图标列表
CImageList ModuleImageList;
然后用Create方法创建图标,并用列表控件的SetImageList方法绑定该图形对象
ProcessImageList.Create(16,16,ILC_COLOR32,0,255);
m_ProcessList.SetImageList(&ProcessImageList,LVSIL_SMALL);
然后就是在取进程循环中将ExtractIcon函数返回的图标句柄hIcon,用图形对象的Add方法添加到图形对象上面如:
nImage=ProcessImageList.Add(hIcon);
然后在插入新项时记得要指定第三个nImage参数否则,图标会显示不出来
m_ProcessList.InsertItem(index,"1",nImage);
对于ExtractIcon返回图标为空的即没有图标的exe程序添加默认程序图标 ,dll模块同样设定为默认dll图标。需要在资源中添加这两种图标。
4.关于列表控件排序的问题
BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData );
列表控件类提供了SortItems方法来排序,2个参数为一个排序的回调函数和一个传递给回调函数的参数:
pfnCompare (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
回调函数有三个参数参数一和二为比较的目标串指针,参数3和SortItem的第二个参数一致,MSDN中提到:
The comparison function is called during the sort operation each time the relative order of two list items needs to be compared
每次有两个列表项做比较时会调用回调函数。可知SortItems函数会自动调用回调函数,可是回调函数的目标串指针怎么赋值呢?
需要注意的是LVITEM结构成员中有个LPARAM lParam成员变量MSDN中有提到:
If you use the LVM_SORTITEMS message, the list-view control passes this value to the application-defined comparison function.即当你使用SortItems函数时,这个成员会被传递给回调函数。所以在调用排序函数之前需要你为LVITEM结构的lParam成员赋值两种方法,
一可以通过定义LVITEM对象直接给对象的lParam赋值如:
LVITEM lv;
lv.lParam=xx;
二、通过SetItemData给lParam赋值
BOOL SetItemData( int nItem, DWORD dwData );
参数二的描述中有一句This value is the lParam member of the LVITEM structure即第二个参数正是为LVITEM结构的lParam参数赋值。也就是获取指定nItem行的数据,可以通过循环分别将列表中的行数据赋值给lParam参数,来完成回调函数的比较
如下:
for (int i=0; i<m_ProcessList.GetItemCount(); i++)
m_ProcessList.SetItemData(i,i);
m_ProcessList.SortItems(CompareProc, (LPARAM)&m_ProcessList);程序中定义了一个布尔值的变量来标识按照正序排序还是倒序排序,具体代码查看附件吧,个人感觉MFC写程序比较松散,没有Win32感觉好~当然更没有汇编舒服
程序在WindowsXP SP3和Windows7下测试通过,大家也可以帮忙看下,如果有问题请反馈谢谢,后序会将各个功能模块集合到一起。谢谢收看~
程序文件 TaskMsgMFC.exe.txt
源文件 TaskMsgMFCDlg.cpp.txt
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- Filmage Screen 软件安全风险分析报告 10537
- 2021 KCTF 第五题 华山论剑cc 5396
- fuzzing 函数时, 指针参数的困惑~ 5328
- arm平台二进制文件vmp保护 3708
- crackme一枚 6914