CE5.0关于设备管理器的源码分析

Cheat Engine 6.7 源码深度解析与实战 本文还有配套的精品资源,点击获取 简介:Cheat Engine 是一个开源的调试工具,用于游戏修改和内存调试,由David Kerkhoff开发。Cheat Engine 6.7版本的源码提供了一个深入了解逆向工程、内存操作和游戏开发的平台。源码包括内存扫描、动态地址跟踪、反调试技术、汇编指令集支持、脚本语言、图形用户界面、多线程和并发、内存注入以及调试API等多个技术方... 阅读详情

 系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如usb鼠标)?系统是怎么控制设备的电源的?

CE管理设备的程序叫做DEVICE.EXE,这是一个独立的用户级进程,它主要负责跟踪,维护系统的设备信息并对设备资源进行调配.设备管理器包括即插即用设备管理,电源管理,io资源管理等等.

结构示意图:

目录树:c:/WINCE500/PRIVATE/WINCEOS/COREOS/DEVICE/

[DEVCORE]设备管理器的核心代码部分.

Devapi.c

Devcore.c

Devfile.c

Devfsd.c

Devload.c

Devpnp.c

Celogdev.h

[DEVMAIN]程序入口点.

devmain.c

[INC]头文件

Devmgrif.h

Devmgrp.h

Devzones.h

Iormif.h

Pmif.h

[IORM]io资源管理

Iorm.c

[NOPMIF]电源管理模块接口(这里是不要电源管理模块的'空'接口)

Nopmif.c

[PMIF]电源管理模块接口

Pmif.c

源码分析按照先后执行顺序来分析源代码.

在[DEVMAIN]中有一个devmain.c的代码,这是device.exe的入口点.如同标准c的main()函数所在,因为是windows所以入口点是WinMain()这样的函数.在WinMain()内没有其他内容,只调用了StartDeviceManager()这个函数.

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmdShow)

{

  int status;

  status = StartDeviceManager(hInst, hPrevInst, lpCmdLine, nCmdShow);

  return status;

}

前面WinMain()调用的StartDeviceManager()函数位于devcore.c. 这个函数初始化设备管理器,电源管理器,IO资源管理,然后启动设备管理器,开始负责设备驱动的加载和卸载工作.

int WINAPI StartDeviceManager(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow)

{

  HINSTANCE hCeddkDll;

  HANDLE hEvent;

  if(IsAPIReady(SH_DEVMGR_APIS))

  {

    return 0;

  }

  DEBUGREGISTER(NULL);

  DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Starting boot phase 1/n")));

  // PHASE 1

  g_BootPhase = 1; //用一个全局变量来表示现在处于启动的哪个阶段.一共有3个阶段.

   

  // 0表示还没有开始启动;1表示在搜索注册表的值;2表示在加载设备;

  // 3表示已经开始正常运行了.

  InitOOMSettings(); // 初始化OOM.

  InitializeListHead(&g_DevChain);// 初始化常规状态设备列表

  InitializeListHead(&g_ActivatingDevs); // 初始化激活的已经注册的设备列表

  InitializeListHead(&g_DyingDevs); // 初始化消亡状态的设备列表

  InitializeListHead(&g_CandidateDevs); // 初始化正在加载的设备驱动列表.

  g_hCleanEvt = CreateEvent(NULL, FALSE, FALSE, NULL);

  g_hDevApiHandle = CreateAPISet("WFLD", NUM_FDEV_APIS, FDevApiMethods, FDevApiSigs);// 向系统注册api

  g_hDevFileApiHandle = CreateAPISet("W32D", NUM_FAPIS, DevFileApiMethods, DevFileApiSigs); // 向系统注册api

  RegisterAPISet(g_hDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE);

  InitializePnPNotifications(); // 这个程序将调用StartDeviceNotifyThread()

  // 这将启动一个线程.它的具体实现在devpnp.c文件中.

  InitializeCriticalSection(&g_devcs); // 初始化临界区.

  ResourceInitModule(); // 初始化一个全局变量gdwMaxDenseResources

  // 根据注册表来初始化设备管理资源

  ResourceInitFromRegistry(TEXT("Drivers//Resources"));

  SetPowerOffHandler((FARPROC) DevMgrPowerOffHandler);

  RegisterAPISet(g_hDevApiHandle, SH_DEVMGR_APIS);

  InitDeviceFilesystems();

  // Indicate that the device manager is up and running

  hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/DevMgrApiSetReady"));

  DEBUGCHK(hEvent != NULL);

  if (hEvent != NULL)

  {

    SetEvent(hEvent);// 设置一个全局事件.通知别的程序设备管理器api已经准备好了.

                    // 在其他的应用里面,使用设备管理器api前,如果希望确认设备管理器

                    // 的api已经注册好,它会等待这样一个事件.

    CloseHandle(hEvent);

}

// Calibrate stall counter that is used for StallExecution

// 以下代码调用ceddk.dll里面的fnCalibrateStall()函数.

hCeddkDll = LoadLibrary (TEXT("ceddk.dll"));

if (NULL != hCeddkDll)

{

    pCalibrateStallFn fnCalibrateStall = (pCalibrateStallFn)/GetProcAddress(hCeddkDll, TEXT("CalibrateStallCounter"));

    if (!fnCalibrateStall)

    {

      DEBUGMSG(ZONE_BOOTSEQ,(L"GetProcAddress failed on ceddk.dll/r/n"));

      FreeLibrary(hCeddkDll);

    }

    else

    {

      fnCalibrateStall();

    }

}

  // Call the power manager initialization entry point

  PM_Init(); // 初始化电源管理模块.电源管理模块是一个pm.dll.它也被device.exe调用.这里// 暂时不打算涉及电源管理部分.简单来说:  在PM_Init()函数里面会启动3个线程,

  // PnpThreadProc,ResumeThreadProc, ActivityTimersThreadProc

  // 它们各自负责监控即插即用,Resume,和激活定时器

  PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);//设置系统电源开.

// See if we are going to have two boot phases

// 根据注册表内容,决定采用怎样的加载过程.

// 如果存在SYSTEM/BootPhase1.分2个步骤来加载:

// 先DevloadInit()加载一次,然后等待通知后,继续调用InitDevice()加载.

// 如果没有SYSTEM/BootPhase1,则调用DevloadInit()一次完成.

// 也许是满足一些需要2次加载设备的情况,所以留下这个功能.

  hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPhase1"));

  if (hEvent != NULL)

  {

    // Load phase 1 drivers from the boot registry

    DevloadInit(); // 加载设备.DevloadInit()函数位于devload.c,它首先删除注册表里面

                  // Device/Active,然后调用InitDevices()函数加载设备驱动.

  // Signal boot phase 1 complete

  SetEvent(hEvent); // 发出通知,阶段1已经完成.

  CloseHandle(hEvent);

  // Wait for phase 2 of the boot to begin

  // 等待通知后进入阶段2

  hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("SYSTEM/BootPhase2"));

  DEBUGCHK(hEvent);

  if (hEvent)

  {

    DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Started, waiting for boot phase 2/r/n")));

    WaitForSingleObject(hEvent, INFINITE);

    CloseHandle(hEvent);

  }

// Load any new drivers from the persistent registry.Since the

// registry may have changed, update the power state for any devices

// that need it.

  DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Second-phase driver load/r/n")));

  g_BootPhase = 2;

  PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);

  InitDevices(NULL); // DevInit()加载会先清空注册表Acitve下的内容,

// 第二次加载不能把前面一次的清空,所以这里不能用DevInit().

  DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Startup sequence complete/r/n")));

  SignalStartedUsingReg(); // SignalStarted call with the right args

  }

  else

  {

    DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: No boot registry - skipping to boot phase 2/n")));

    g_BootPhase = 2;

    DevloadInit();

    SignalStarted(_wtol(lpCmdLine));

  }

// Boot phase 3 isn't any different from phase 2; just marks that we got here.

  DEBUGMSG(ZONE_BOOTSEQ,(TEXT("DEVICE: Finished loading primary drivers - entering boot phase 3/n")));

  g_BootPhase = 3; // 进入阶段3,同时也标志设备管理器开始运行了.

  CELOG_DeviceFinished (); // 记录日志.

  while (1)

  {

      WaitForSingleObject(g_hCleanEvt, INFINITE);

      // check for auto-deregister devs first as they may end up queuing

      // themselves on the dying devs list

      ProcessAutoDeregisterDevs();

      ProcessDyingDevs();

      ProcessDyingOpens();

  }

  return 1;// should not ever be reached

}

加载设备的函数,DevloadInit()事实上也是调用InitDevices来实现,只不过事先清空了Acitve下的注册表内容

void DevloadInit(void)

{

  DEBUGMSG(ZONE_INIT, (TEXT("DEVICE!DevloadInit/r/n")));

  #define PHASE_1_BUSNAME TEXT("BuiltInPhase1")

//

// Delete the HLM/Drivers/Active key since there are no active devices at

// init time.

// 清空注册表Active下的内容.

RegDeleteKey(HKEY_LOCAL_MACHINE, s_ActiveKey);

#ifdef DEBUG

v_NextDeviceNum = 0xFFFFFFF0;// expect wraparound

#else// DEBUG

v_NextDeviceNum = 1;

#endif// DEBUG

g_bSystemInitd = FALSE;

InitDevices(PHASE_1_BUSNAME);

}

InitDevices(LPCTSTR lpBusName )

{

HKEY RootKey;

DWORD status;

DWORD ValType;

DWORD ValLen;

TCHAR RootKeyPath[REG_PATH_LEN];

TCHAR BusName[DEVKEY_LEN];

REGINI reg[1];

DWORDdwRegCount=0;

// Open HLM/Drivers key

//打开注册表HLM/Drivers.

status = RegOpenKeyEx(

HKEY_LOCAL_MACHINE,

DEVLOAD_DRIVERS_KEY, //DEVLOAD_DRIVERS_KEY= "Drivers"

0,

0,

&RootKey);

if (status != ERROR_SUCCESS)

{

  DEBUGMSG(ZONE_ROOT|ZONE_ERROR,(TEXT("DEVICE!InitDevices RegOpenKeyEx(%s) returned %d./r/n"),DEVLOAD_DRIVERS_KEY, status));

  return;

}

//

// Look for root key value; if not found use current Root Key as default,

// otherwise open new root key

// 查询注册表中 RootKey的值,一般这个值是Devices/BuildIn.将查询的值保存到RootKeyPath.

//[HKEY_LOCAL_MACHINE/Drivers]

    "RootKey"="Drivers//BuiltIn"

// 如果没有指定,则使用Devices来替代.

ValLen = sizeof(RootKeyPath);

status = RegQueryValueEx(

RootKey,

DEVLOAD_ROOTKEY_VALNAME, //DEVLOAD_ROOTKEY_VALNAME =RootKey

NULL,

&ValType,

(PUCHAR)RootKeyPath,

&ValLen);

RootKeyPath[ARRAYSIZE(RootKeyPath) - 1] = 0;

if (status != ERROR_SUCCESS)

{

// Root key value not found, thus root key is Drivers

_tcscpy(RootKeyPath, DEVLOAD_DRIVERS_KEY); // 没有找到,使用Devices来替代.

}

// Close previous root key

RegCloseKey(RootKey);

DEBUGMSG(1,(L"DEVICE!InitDevices: Root Key is %s./r/n",RootKeyPath));

// 为ActiveDeviceEx准备参数reg. 如果输入参数lpBusName指定了,则从参数lpBusName获得,

// 否则从注册表中读取.

if (lpBusName!=NULL)

{

reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;

reg[0].dwType= DEVLOAD_BUSNAME_VALTYPE;

reg[0].pData= (PBYTE) lpBusName ;

reg[0].dwLen= (_tcslen( lpBusName ) + 1) * sizeof(TCHAR);

dwRegCount = 1;

}

else

{

  status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RootKeyPath,0,0, &RootKey);

  if (status == ERROR_SUCCESS )

  {

    ValLen = sizeof( BusName);

    status = RegQueryValueEx(RootKey,DEVLOAD_BUSNAME_VALNAME,NULL,&ValType,(PUCHAR)BusName,&ValLen);

    if (status == ERROR_SUCCESS && ValType==DEVLOAD_BUSNAME_VALTYPE)

    {

      // We found Bus Name. This is new bus driver model. So we use new format.

      BusName[DEVKEY_LEN-1] = 0;

      reg[0].lpszVal = DEVLOAD_BUSNAME_VALNAME;

      reg[0].dwType= DEVLOAD_BUSNAME_VALTYPE;

      reg[0].pData= (PBYTE)BusName;

      reg[0].dwLen=ValLen;

      dwRegCount = 1;

      }

  // Close previous root key

  RegCloseKey(RootKey);

  }

}

// Someday we'll want to track the handle returned by ActivateDevice so that

// we can potentially deactivate it later. But since this code refers only to

// builtin (ie, static) devices, we can just throw away the key.

if (dwRegCount)

  ActivateDeviceEx(RootKeyPath,reg,dwRegCount,NULL);

else

  ActivateDevice(RootKeyPath, 0);

}// InitDevices

至此,已经明确了系统是通过InitDevice()来加载驱动,更具体的InitDevice()会调用ActivateDeviceEx()来加载驱动,但是,这里只加载了一个驱动啊,难道系统就只加载一次?

这个唯一被加载的驱动是BusEnum.dll(在CE4.2是RegEnum.dll)这个驱动位于public下,它枚举了BuiltIn下所有的设备,逐个加载,并在Active下记录成功加载的设备.


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/dhdahai/archive/2009/06/09/4253891.aspx

Cheat Engine 6.3源码深入解析 Cheat Engine(简称CE)是一款在游戏作弊社区中广受欢迎的开源内存扫描、调试和反汇编工具。它由一个荷兰程序员Merijn Bellekom开发,旨在帮助开发者和爱好者理解、修改和调试软件,特别是视频游戏。内存编辑器是CE的核心功能之一,它允许用户直接访问和修改进程的内存空间。自动汇编器提供了一种便捷的方式来生成汇编代码,使得用户能够快速修改游戏或应用程序的行为。扫描器模块负责执行内存扫描,以便用户可以找到特定的值或地址。脚本引擎则是通过Lua脚本扩展CE功能的一个强大工具。 阅读详情

相关推荐

CE模块源代码分析和运行原理

CE模块源代码分析和运行原理CE模块源代码分析和运行原理CE模块源代码分析和运行原理CE模块源代码分析和运行原理

[ docker-ce源码分析系列 ]docker build源码简析

1 概述: 1.1 环境 版本信息如下: a、操作系统: centos 7.6,amd64 b、服务器docker版本:v18.09.2 c、docker的存储驱动: overlay2 2 源码简析: 用户执行docker build命令,本篇文章简要分析docker daemon构建镜像的过程。 2.1 服务端注册路由initRoutes() r.postBuild就是处理docker build请求的方法。 func (r *buildRouter) initRoutes() { r.routes

nangonghen的博客 928

CE7.4源码 CheatEngine7.4源码

添加和更改: AA 模板现在在按住 Ctrl 时生成 14 字节的 jmp 脚本 "找到代码"对话框:立即替换 nop 和原始之间的切换。还可以防止重复 改进了键盘控制到内存视图中的十六进制视图。现在,您可以在使用光标移动时按住 shift 键 laststate 不再保存在表中(除非 ctrl 已关闭) 为 dbvm 函数添加了一些空间,因此不太可能单击它们 您现在可以手动删除保存的结果 调试器附加超时窗口现在将显示某些调试器接口上的状态 32 位目标中 64 位的模块被更清楚地标记为 单声道在断开连接后不会尝试重新连接 lua: 固定副本内存模式 2

[ docker-ce源码分析系列 ]创建(create)容器简析

1 概述: 1.1 环境 版本信息如下: a、操作系统: centos 7.6,amd64 b、服务器docker版本:v18.09.2 2 源码简析: 用户docker run,client至多会向docker daemon发起三次远程调用,分别是创建(拉取)镜像、创建容器、启动容器。本篇文章分析创建容器这个远程调用。 2.1 注册路由initRoutes() func (r *containerRouter) initRoutes() { r.routes = []router.Route{

nangonghen的博客 1094

教大家修改CE,如何去做自己一个CE

教大家修改CE,如何去做自己一个CE教大家修改CE,如何去做自己一个CE教大家修改CE,如何去做自己一个CE教大家修改CE,如何去做自己一个CE

CE6.8.1源码,打造属于自己的CE

CheatEngine6.8.1源码,可以用lazarus打开重新编译,打造自己的CE,具体教程请百度搜索就有了

CE5.0 驱动程序:设备管理器的源码分析

系统下面许多设备,比如键盘,串口,触摸屏,硬盘......这些设备什么时候被系统使用的?这些设备怎样被系统使用的?加载过程是怎么样的?设备如何加入系统协同工作的?为什么系统能检测到并使用即插即用的设备(如usb鼠标)?系统是怎么控制设备的电源的?CE管理设备的程序叫做DEVICE.EXE,这是一个独立的用户级进程,它主要负责跟踪,维护系统的设备信息并对设备资源进行调配.设备管理器包括即插即用设备管...

jandroid 118

CE源码大合集

网上收集而来,3个易语言CE源代码。高手综合一下应该更好用。

USB转232驱动安装实战案例(含源码分析)

深入讲解USB转232驱动安装的完整流程,结合实际案例剖析关键步骤与常见问题。通过源码分析帮助理解底层通信机制,提升调试效率,是掌握usb转232驱动安装的实用指南。

weixin_26854475的博客 592

windows 设备管理器 源代码

windows 设备管理器 源代码 实现windwos设备枚举,查询,禁用,启用等功能。

PyTorch ModelNet点云数据集加载实战:从下载到Dataset类完整实现

在三维视觉与点云处理领域,数据集是算法研发的基石。ModelNet作为三维物体分类的基准数据集,其地位类似于图像领域的MNIST,是入门和评估模型性能的通用标准。理解其数据格式与加载原理,是进行点云分类、分割等任务的关键前置步骤。通过PyTorch的Dataset类,开发者可以构建高效的数据管道,将原始点云文件转换为神经网络可直接处理的张量格式,这一过程涉及数据采样、归一化、特征组装等核心操作,直接影响模型的训练效率和最终性能。本文聚焦于ModelNet10/40数据集,详细解析其目录结构,并提供一套稳健的

weixin_29032337的博客 280
上一篇: Windows下动态内存分配方式
下一篇: 2440上U口的WIFI与U盘不能同时使用的解决
alien75
博客等级 码龄25年 195粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值