Hacking Windows CE: 如何从线程ID获取线程名称

Wince系统任务调度机制 调度概述 调度是多任务操作系统中的一个基本概念。也是多任务操作系统内核必须提供的一种基本服务。调度的基本对象是任务(有些操作系统中也称为进程或线程),调度负责为系统中的任务分配当前CPU时间,决定当前CPU使用权由哪一个任务占用。调度大大简化了应用程序的设计,用户可以将一个应用分解成不同的任务,各任务的执行由多任务操作系统内核提供的调度服务管理。 Wince是一个基于优先级可抢占+时间片... 阅读详情

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

DWORD WINAPI NtQueryInformationThread(
                HANDLE ThreadHandle,
                THREAD_INFORMATION_CLASS ThreadInformationClass,
                PVOID ThreadInformation,
                ULONG ThreadInformationLength,
                PULONG ReturnLength
                );
获取线程入口地址可用:


DWORD GetThreadStartAddress(DWORD dwThreadId)
...{
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
    DWORD retaddr, len, error;
    retaddr = len = 0;
    error = NtQueryInformationThread( hThread, 9, &retaddr, sizeof(retaddr), &len );
    CloseHandle(hThread);
    if( error != 0 )
        retaddr = 0;
    return retaddr;
}
在Windows CE上就没这么幸运了,没有任何现成的API可用。官方Windows CE Base Team的blog对这个问题的回答是可以用Remote Kernel Tracker,不过这需要你build一个特殊的kernel image,enable一些profiler功能-这在显示的问题诊断中显然是不实际的。那么有没有办法不需要什么特殊的配置就可像Windows桌面操作系统那样获得入口地址呢?有是有的,不过需要一些hack手段。仔细研究CE下的Thread内核数据结构,就会发现Thread结构中有一项是记录线程入口地址的。

typedef struct Thread ...{
    DWORD _1[3];
    PPROCESS pProc; /**//* 0C: pointer to current process */
    PPROCESS pOwnerProc; /**//* 10: pointer to owner process */
    DWORD _2[18];
    DWORD dwStartAddr; /**//* 5c: thread PC at creation, used to get thread name */
    DWORD _3[10];
}THREAD, *PTHREAD; /**//* Thread */
因此要做的就是想办法根据线程ID或handle得到这个数据。再研究,发现线程的Thread内核数据结构可通过句柄得到:


PTHREAD pTh = HandleToThread(ThreadHandle);
而且,在Windows CE下,线程ID和其handle的值是一样的!!因此我们可以写一个这样的函数从线程ID拿到入口地址:


DWORD GetThreadStartAddress(DWORD dwThreadId)
...{
    DWORD dwStartAddress = 0;
    BOOL fOldMode = SetKMode(TRUE);
    PTHREAD pTh = HandleToThread((HANDLE)dwThreadId);
    if (pTh)
    ...{
        dwStartAddress = (DWORD)MapPtrToProcess((LPVOID)pTh->dwStartAddr, pTh->pOwnerProc->hProc);
    }
    return dwStartAddress;
}
为了使用这些内核数据结构,我们还需要另外一些辅助结构和函数,比较完整的代码如下。当然,官方肯定是不建议这么做的,但是重要的是解决问题,你说呢。

typedef struct Process ...{
    DWORD _1[2];
    HANDLE hProc; /**//* 08: handle for this process, needed only for SC_GetProcFromPtr */
}PROCESS, *PPROCESS;
typedef struct Thread ...{
    DWORD _1[3];
    PPROCESS pProc; /**//* 0C: pointer to current process */
    PPROCESS pOwnerProc; /**//* 10: pointer to owner process */
    DWORD _2[18];
    DWORD dwStartAddr; /**//* 5c: thread PC at creation, used to get thread name */
    DWORD _3[10];
}THREAD, *PTHREAD; /**//* Thread */

typedef struct cinfo ...{
    char acName[4]; /**//* 00: object type ID string */
    uchar disp; /**//* 04: type of dispatch */
    uchar type; /**//* 05: api handle type */
    ushort cMethods; /**//* 06: # of methods in dispatch table */
    const PFNVOID *ppfnMethods;/**//* 08: ptr to array of methods (in server address space) */
    const DWORD *pdwSig; /**//* 0C: ptr to array of method signatures */
    PPROCESS pServer; /**//* 10: ptr to server process */
} CINFO; /**//* cinfo */
typedef CINFO *PCINFO;

typedef struct _HDATA HDATA, *PHDATA;
struct _HDATA ...{
    DWORD _1[2]; /**//* 00: links for active handle list */
    HANDLE hValue; /**//* 08: Current value of handle (nonce) */
    DWORD lock; /**//* 0C: access information */
    DWORD ref; /**//* 10: reference information */
    const CINFO *pci; /**//* 14: ptr to object class description structure */
    PVOID pvObj; /**//* 18: ptr to object */
    DWORD dwInfo; /**//* 1C: extra handle info */
}; /**//* 20: sizeof(HDATA) */

#ifdef x86
struct KDataStruct ...{
    LPDWORD lpvTls; /**//* 0x000 Current thread local storage pointer */
    HANDLE ahSys[NUM_SYS_HANDLES]; /**//* 0x004 If this moves, change kapi.h */
    DWORD _1[4];
    ulong handleBase; /**//* 0x094 base address of handle table */
}; /**//* KDataStruct */
#endif
#ifdef ARM
struct KDataStruct ...{
    LPDWORD lpvTls; /**//* 0x000 Current thread local storage pointer */
    HANDLE ahSys[NUM_SYS_HANDLES]; /**//* 0x004 If this moves, change kapi.h */
    DWORD _1[6];
    ulong handleBase; /**//* 0x09c handle table base address */
}; /**//* KDataStruct */
#endif

#define HandleToThread(h) ((THREAD *)GetObjectPtrByType((h),SH_CURTHREAD))
#define HANDLE_ADDRESS_MASK 0x1ffffffc

void h2p(HANDLE h, 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;
}

PVOID GetObjectPtrByType(HANDLE h, int type)
...{
    PHDATA phd;
    h2p(h, phd);
    return (phd && phd->pci && phd->pci->type==type) ? phd->pvObj : 0;
}

extern "C" LPVOID WINAPI MapPtrToProcess(LPVOID lpv, HANDLE hProc);
extern "C" BOOL WINAPI SetKMode(BOOL fMode);

DWORD GetThreadStartAddress(DWORD dwThreadId)
...{
    DWORD dwStartAddress = 0;
    BOOL fOldMode = SetKMode(TRUE);
    PTHREAD pTh = HandleToThread((HANDLE)dwThreadId);
    if (pTh)
    ...{
        dwStartAddress = (DWORD)MapPtrToProcess((LPVOID)pTh->dwStartAddr, pTh->pOwnerProc->hProc);
    }
    return dwStartAddress;
}

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/singlerace/archive/2006/11/11/1379453.aspx

魔力宝贝CGA辅助开发包:C++开源框架与脚本自动化实战 在游戏开发与自动化领域,内存读写和进程交互是核心技术基础,其原理是通过操作系统API直接访问和修改其他进程的内存数据,实现外部控制。这项技术的核心价值在于能够构建高度定制化的辅助工具,广泛应用于游戏自动化、软件测试和数据监控等场景。C++因其高性能和底层系统调用能力,成为实现这类工具的首选语言,它能确保数据读取的实时性和操作响应的低延迟。通过模块化设计,将数据采集、逻辑控制和用户接口分离,可以大幅提升代码的可维护性和扩展性。在此基础上,集成Lua等脚本引擎,允许开发者用高级语言编写业务逻辑,实现了灵活的热更 阅读详情

相关推荐

WinCE下多线程编程

WinCE下进行多线程编程,驱动外设.如led、adc、键盘、鼠标等

Win32Thread

Win32Thread是指向_W32THREAD结构体的指针,通过这个结构体可以获得钩子所在进程ID和线程ID.该结构体定义如下。   typedef struct _W32THREAD { PVOID pEThread ; //该指针用以获得进程ID和线程ID ULONG RefCount ;ULONG ptlW32 ;ULONG pgdiDcattr ;ULONG pgdiBrushAttr

wetgsg的专栏 1823

告别NEDC!手把手教你将CLTC/WLTP等最新工况文件导入AVL Cruise(附资源包)

本文详细指导如何将CLTC、WLTP等最新工况文件导入AVL Cruise软件,替代传统的NEDC工况。从资源获取、文件预处理到分步导入指南,再到常见问题排查,帮助工程师高效完成汽车仿真性能评估。附赠全球主流工况文件资源包,助力精准仿真分析。

weixin_30374009的博客 461

Windows CE 进程、线程和内存管理

进程、线程、内存管理是一个内核最基本的服务,也是一个内核最主要的组成部分。这几方面的知识是一个软件开发人员必须掌握的基础知识。虽然一个人不懂这些知识也能编写简单的程序,但这样的程序只能算是皮毛。掌握了进程、线程和内存管理方面的知识,就能够充分利用操作系统内核提供的服务,提高你编写的软件的执行效率、更节省资源、更健壮。顺便说一下,在Windows CE.net下可以运行用Visual Studio.

sillyrandylau的专栏 1392

python指纹识别算法(亲测代码可用)

python指纹识别算法

2301_76482796的博客 3078

基于MATLAB实现语音信号MFCC特征提取(附完整代码)

你有没有想过你的智能手机是如何理解语音指令的?或者 Alexa 和 Siri 等语音助手如何处理您的命令?这种卓越能力背后的机制在很大程度上归功于一种称为 Mel 频率倒谱系数 (MFCC) 的方法。语音识别技术允许机器解释人类语音,将口语转换为计算机可以操纵的格式。这项技术对于开发交互式和响应式 AI 至关重要,例如声控助手、自动化客户服务系统和实时翻译服务。MFCC 代表 Mel 频率倒谱系数。这是用于自动语音和说话人识别的功能。

baidu_34971492的博客 1313

渗透测试 ( 0 ) --- XSS、CSRF、文件上传、文件包含、反序列化漏洞

渗透测试 --- http协议、XSS、CSRF、文件上传、文件包含、反序列化漏洞

freeking101的博客 5540

把 Client 当成 ABAP 系统的多租户底座:从 sy-mandt 到 CDS_CLIENT 的隔离机制与工程实践

本文深入解析SAP ABAP系统中Client概念的本质与应用。Client不仅是数据表的MANDT字段,更是会话级别的隔离边界,贯穿用户登录、授权和数据访问控制全过程。文章从ABAP SQL的隐式Client处理机制出发,详细介绍了USING CLIENT、USING ALL CLIENTS等安全跨客户端访问方式,并对比了传统CLIENT SPECIFIED的风险。同时阐述了ABAP CDS中@ClientHandling注解的类型与算法选择,包括#AUTOMATED自动拼接和#SESSION_VARIA

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 182

windows下如何查看某个进程有多少个线程,及各个线程的CPU、名称等详细信息

windows下如何查看某个进程有多少个线程,及各个线程的CPU、名称等详细信息

Echo的博客 1万+

基于STM32设计的智能水母投喂器(华为云IOT)_170

本项目利用STM32单片机控制各种传感器和水泵等设备,能够自动检测和调整水温和水质等参数,自动换水,自动供氧等等,充分满足了水母的养殖要求和需要。同时,根据水母喜欢的光环境,添加了RGB氛围灯,以及可以手动控制的喂食器等功能,提升了水母养殖的便利性和趣味性。

8806

基于FPGA的FIR数字滤波器设计

clear;close all fc=1/4;fs=5/16; %输入给定指标 Rp=3;As=60;Fs=2; f=[fc,fs];m=[1,0]; %计算remezord函数所需参数f,m,dev dev=[(10^(Rp/20)-1)/(10^(Rp/20)+1),10^(-As/20)]; [N,fo,mo,W]=remezord(f,m,dev,Fs); %确定remez函数所需参数 hn=remez(N,fo,mo,W);...

FPGA/MATLAB学习教程/源码/项目合作开发 9454

关于线程运行的查看

线程的运行是交替执行的 谁先谁后,是不受我们控制的 查看进程线程的方法 windows操作系统下 任务管理器可以查看进程和线程数,也可以

weixin_58104242的博客 1268

Motoman机器人离线编程——Motocom32开发简介

欢迎关注Jungle的Motoman机器人离线编程专栏系列文章: Motoman机器人离线编程——Motocom32开发简介 Motoman机器人离线编程——Visio Studio环境配置 Motoman机器人离线编程——Motocom32库函数的使用与封装 Motoman机器人离线编程——Motocom32参考文献及注意事项 Motoman机器人离线编程——MotocomES介绍 ...

冯Jungle的个人博客 8713

Cheat Engine 创建线程

打开游戏 扫描出阳光地址 打开自动汇编 激活测试 每次激活,阳光都会自增

超哥的专栏 2397

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

得到线程入口地址的方式

要获取入口地址,可以用Native API: NtQueryInformationThread,以ThreadQuerySetWin32StartAddress为参数 具体代码: .h: #pragma once typedef LONG NTSTATUS; typedef NTSTATUS (WINAPI *NTQUERYINFORMATIONTHREAD)( HANDLE Th...

weixin_30909575的博客 655

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

windows查看线程状态及内存情况

visualvm打开JVisualVM(能够监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象,反向查看分配的堆栈,详细信息参见JVisualVM简介)

weixin_45815061的博客 1069

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

wince:WinCE线程同步

原文地址:wince:WinCE线程同步作者:不停息的脚步我转载于:http://www.a3gs.com/BookViews.asp?InfoID=2407&ClassID=800   1、线程概述WinCE是有优先级的多任务操作系统,它允许重功能、进程在相同时间的系统中运行,WinCE支持最大的32位同步进程。一个进程包括一个或多个线程,每个线程代表进程的一个独立部分,而一个线程被指定为进程的

caoshunxin01的专栏 819

CE 线程小记

wince中,在编写线程的时候,发现一个问题。如果在创建线程的时候不设置线程的优先级,会发现线程创建了两个及以上就会出现卡的情况。当设置了优先级后,就没有这样的情况了。在此记录一下该情况,免得到时忘记了。 下面是个例子: DWORD idThread; // 创建UI处理线程 hUiThread = ::CreateThread(NULL, 0, UiTread, NULL, CREATE...

mmdev 490

如何查看线程的运行状态

问题:我的程序在其内部创建并执行了多个线程,我怎样才能在该程序创建线程后监控其中单个线程?我想要看到带有它们名称的单个线程详细情况(如,CPU/内存使用率)。 线程是现代操作系统上进行并行执行的一个流行的编程方面的抽象概念。当一个程序内有多个线程被叉分出用以执行多个流时,这些线程就会在它们之间共享特定的资源(如,内存地址空间、打开的文件),以使叉分开销最小化,并避免大量高成本的IPC(进程间通信)通道。这些功...

weixin_43763259的博客 8621

获取线程名称方法(2种)

获取线程名称的方法

m0_73944607的博客 2411
上一篇: 简单的调试信息显示程序
下一篇: WINCE应用程序和驱动间通信
alien75
博客等级 码龄25年 195粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值