设为首页 收藏本站
查看: 1348|回复: 0

[经验分享] Hacking Windows CE: 如何从线程ID获取线程名称

[复制链接]

尚未签到

发表于 2016-5-21 11:04:58 | 显示全部楼层 |阅读模式
在一个线程出现异常行为时,比如说CPU占用率过高,抛出异常等,你一定想知道这个线程是由哪个模块创建的。因此无论在哪个操作系统上,获取线程名称是诊断线程相关问题的重要一步。  从线程ID获取线程名称通常的方法是,先获取该线程的入口地址,然后枚举进程内所有已加载模块,最后判断线程入口地址落在哪个加载模块范围内。枚举进程内已加载模块可用Win32标准的CreateToolhelp32Snapshot/Module32First/Module32Next系列ToolHelp  API得到。获取线程入口地址则没有线程的Win32 API可用。不过在Windows NT based操作系统上(包括Windows NT  4.0/2000/XP/2003,等),有一个未公开的Native API可用:NtQueryInformationThread。其声明如下:
DSC0000.gif DWORDWINAPINtQueryInformationThread(
HANDLEThreadHandle,
THREAD_INFORMATION_CLASSThreadInformationClass,
PVOIDThreadInformation,
ULONGThreadInformationLength,
PULONGReturnLength
);


  获取线程入口地址可用:
  
DWORDGetThreadStartAddress(DWORDdwThreadId)
DSC0001.gif DSC0002.gif
...{
DSC0003.gif HANDLEhThread
=OpenThread(THREAD_ALL_ACCESS,FALSE,dwThreadId);
DWORDretaddr,len,error;
retaddr
=len=0;
error
=NtQueryInformationThread(hThread,9,&retaddr,sizeof(retaddr),&len);
CloseHandle(hThread);
if(error!=0)
retaddr
=0;
returnretaddr;
DSC0004.gif }



在Windows CE上就没这么幸运了,没有任何现成的API可用。官方Windows CE Base Team的blog对这个问题的回答是可以用Remote  Kernel Tracker,不过这需要你build一个特殊的kernel  image,enable一些profiler功能-这在显示的问题诊断中显然是不实际的。那么有没有办法不需要什么特殊的配置就可像Windows桌面操作系统那样获得入口地址呢?有是有的,不过需要一些hack手段。仔细研究CE下的Thread内核数据结构,就会发现Thread结构中有一项是记录线程入口地址的。 typedefstructThread...{
DWORD_1[
3];
DSC0005.gif DSC0006.gif PPROCESSpProc;
/**//*0C:pointertocurrentprocess*/
PPROCESSpOwnerProc;
/**//*10:pointertoownerprocess*/
DWORD_2[
18];
DWORDdwStartAddr;
/**//*5c:threadPCatcreation,usedtogetthreadname*/
DWORD_3[
10];
}
THREAD,*PTHREAD;/**//*Thread*/

  因此要做的就是想办法根据线程ID或handle得到这个数据。再研究,发现线程的Thread内核数据结构可通过句柄得到:
  
PTHREADpTh=HandleToThread(ThreadHandle);


而且,在Windows CE下,线程ID和其handle的值是一样的!!因此我们可以写一个这样的函数从线程ID拿到入口地址:  
DWORDGetThreadStartAddress(DWORDdwThreadId)
...{
DWORDdwStartAddress
=0;
BOOLfOldMode
=SetKMode(TRUE);
PTHREADpTh
=HandleToThread((HANDLE)dwThreadId);
if(pTh)
...{
dwStartAddress
=(DWORD)MapPtrToProcess((LPVOID)pTh->dwStartAddr,pTh->pOwnerProc->hProc);
DSC0007.gif }

returndwStartAddress;
}



为了使用这些内核数据结构,我们还需要另外一些辅助结构和函数,比较完整的代码如下。当然,官方肯定是不建议这么做的,但是重要的是解决问题,你说呢。 typedefstructProcess...{
DWORD_1[
2];
HANDLEhProc;
/**//*08:handleforthisprocess,neededonlyforSC_GetProcFromPtr*/
}
PROCESS,*PPROCESS;
typedef
structThread...{
DWORD_1[
3];
PPROCESSpProc;
/**//*0C:pointertocurrentprocess*/
PPROCESSpOwnerProc;
/**//*10:pointertoownerprocess*/
DWORD_2[
18];
DWORDdwStartAddr;
/**//*5c:threadPCatcreation,usedtogetthreadname*/
DWORD_3[
10];
}
THREAD,*PTHREAD;/**//*Thread*/

typedef
structcinfo...{
characName[4];/**//*00:objecttypeIDstring*/
uchardisp;
/**//*04:typeofdispatch*/
uchartype;
/**//*05:apihandletype*/
ushortcMethods;/**//*06:#ofmethodsindispatchtable*/
constPFNVOID*ppfnMethods;/**//*08:ptrtoarrayofmethods(inserveraddressspace)*/
constDWORD*pdwSig;/**//*0C:ptrtoarrayofmethodsignatures*/
PPROCESSpServer;
/**//*10:ptrtoserverprocess*/
}
CINFO;/**//*cinfo*/
typedefCINFO
*PCINFO;

typedef
struct_HDATAHDATA,*PHDATA;
struct_HDATA...{
DWORD_1[
2];/**//*00:linksforactivehandlelist*/
HANDLEhValue;
/**//*08:Currentvalueofhandle(nonce)*/
DWORD
lock;/**//*0C:accessinformation*/
DWORD
ref;/**//*10:referenceinformation*/
constCINFO*pci;/**//*14:ptrtoobjectclassdescriptionstructure*/
PVOIDpvObj;
/**//*18:ptrtoobject*/
DWORDdwInfo;
/**//*1C:extrahandleinfo*/
}
;/**//*20:sizeof(HDATA)*/

#ifdefx86
structKDataStruct...{
LPDWORDlpvTls;
/**//*0x000Currentthreadlocalstoragepointer*/
HANDLEahSys[NUM_SYS_HANDLES];
/**//*0x004Ifthismoves,changekapi.h*/
DWORD_1[
4];
ulonghandleBase;/**//*0x094baseaddressofhandletable*/
}
;/**//*KDataStruct*/
#endif
#ifdefARM
structKDataStruct...{
LPDWORDlpvTls;
/**//*0x000Currentthreadlocalstoragepointer*/
HANDLEahSys[NUM_SYS_HANDLES];
/**//*0x004Ifthismoves,changekapi.h*/
DWORD_1[
6];
ulonghandleBase;/**//*0x09chandletablebaseaddress*/
}
;/**//*KDataStruct*/
#endif

#defineHandleToThread(h)((THREAD*)GetObjectPtrByType((h),SH_CURTHREAD))
#defineHANDLE_ADDRESS_MASK0x1ffffffc

voidh2p(HANDLEh,PHDATA&phdRet)
...{
if((ulong)h<NUM_SYS_HANDLES+SYS_HANDLE_BASE&&(ulong)h>=SYS_HANDLE_BASE)
h
=((KDataStruct*)PUserKData)->ahSys[(uint)h-SYS_HANDLE_BASE];
if(h)
...{
phdRet
=(PHDATA)(((ulong)h&HANDLE_ADDRESS_MASK)+((KDataStruct*)PUserKData)->handleBase);
if(phdRet->hValue!=h)
phdRet
=0;
}

else
phdRet
=0;
}


PVOIDGetObjectPtrByType(HANDLEh,
inttype)
...{
PHDATAphd;
h2p(h,phd);
return(phd&&phd->pci&&phd->pci->type==type)?phd->pvObj:0;
}


extern"C"LPVOIDWINAPIMapPtrToProcess(LPVOIDlpv,HANDLEhProc);
extern"C"BOOLWINAPISetKMode(BOOLfMode);

DWORDGetThreadStartAddress(DWORDdwThreadId)
...{
DWORDdwStartAddress
=0;
BOOLfOldMode
=SetKMode(TRUE);
PTHREADpTh
=HandleToThread((HANDLE)dwThreadId);
if(pTh)
...{
dwStartAddress
=(DWORD)MapPtrToProcess((LPVOID)pTh->dwStartAddr,pTh->pOwnerProc->hProc);
}

returndwStartAddress;
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-219862-1-1.html 上篇帖子: zz如何在Windows上安装多个MySQL 下篇帖子: Windows Server 2008 中的打印管理循序渐进指南
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表