CnSystemDebugControl.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnSystemDebugControl;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:CnPack 组件包不可视组件
  24. * 单元名称:封装了 SystemDebugControl 系统调用的组件单元
  25. * 单元作者:刘啸(liuxiao@cnpack.org)
  26. * 开发平台:PWinXPPro + Delphi 5.01
  27. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7/2005 + C++Build 5/6
  28. * 备  注:参考了网上于旸的 SystemDebugControl 分析文章以及其它网络资源
  29. * 单元标识:$Id$
  30. * 修改记录:2008.09.18 V1.0
  31. * LiuXiao 实现单元
  32. ================================================================================
  33. |</PRE>}
  34. interface
  35. {$I CnPack.inc}
  36. uses
  37. SysUtils, Windows, Classes, CnCommon;
  38. type
  39. _DEBUG_CONTROL_CODE = (
  40. SysDbgDummyZero, // 0,
  41. //以下5个在Windows NT各个版本上都有
  42. SysDbgGetTraceInformation, // 1,
  43. SysDbgSetInternalBreakpoint, // 2,
  44. SysDbgSetSpecialCall, // 3,
  45. SysDbgClearSpecialCalls, // 4,
  46. SysDbgQuerySpecialCalls, // 5,
  47. // 以下是NT 5.1 新增的
  48. SysDbgDbgBreakPointWithStatus, // 6,
  49. //获取KdVersionBlock
  50. SysDbgSysGetVersion, // 7,
  51. //从内核空间拷贝到用户空间,或者从用户空间拷贝到用户空间
  52. //但是不能从用户空间拷贝到内核空间
  53. SysDbgCopyMemoryChunks_0, // 8,
  54. //从用户空间拷贝到内核空间,或者从用户空间拷贝到用户空间
  55. //但是不能从内核空间拷贝到用户空间
  56. SysDbgCopyMemoryChunks_1, // 9,
  57. //从物理地址拷贝到用户空间,不能写到内核空间
  58. SysDbgCopyMemoryChunks_2, // 10,
  59. //从用户空间拷贝到物理地址,不能读取内核空间
  60. SysDbgCopyMemoryChunks_3, // 11,
  61. //读写处理器相关控制块
  62. SysDbgSysReadControlSpace, // 12,
  63. SysDbgSysWriteControlSpace, // 13,
  64. //读写端口
  65. SysDbgSysReadIoSpace, // 14,
  66. SysDbgSysWriteIoSpace, // 15,
  67. //分别调用RDMSR和WRMSR
  68. SysDbgSysReadMsr, // 16,
  69. SysDbgSysWriteMsr, // 17,
  70. //读写总线数据
  71. SysDbgSysReadBusData, // 18,
  72. SysDbgSysWriteBusData, // 19,
  73. SysDbgSysCheckLowMemory, // 20,
  74. // 以下是NT 5.2 新增的
  75. //分别调用_KdEnableDebugger和_KdDisableDebugger
  76. SysDbgEnableDebugger, // 21,
  77. SysDbgDisableDebugger, // 22,
  78. //获取和设置一些调试相关的变量
  79. SysDbgGetAutoEnableOnEvent, // 23,
  80. SysDbgSetAutoEnableOnEvent, // 24,
  81. SysDbgGetPitchDebugger, // 25,
  82. SysDbgSetDbgPrintBufferSize, // 26,
  83. SysDbgGetIgnoreUmExceptions, // 27,
  84. SysDbgSetIgnoreUmExceptions // 28
  85. );
  86. DEBUG_CONTROL_CODE = _DEBUG_CONTROL_CODE;
  87. TIOStruct = record
  88. IoAddr: DWORD;
  89. Reserved1: DWORD;
  90. pBuffer: Pointer;
  91. NumBYTEs: DWORD;
  92. Reserved4: DWORD;
  93. Reserved5: DWORD;
  94. Reserved6: DWORD;
  95. Reserved7: DWORD;
  96. end;
  97. _MEMORY_CHUNKS = record
  98. Address: ULONG;
  99. Data: Pointer;
  100. Length: ULONG;
  101. end;
  102. MEMORY_CHUNKS = _MEMORY_CHUNKS;
  103. PMEMORY_CHUNKS = ^_MEMORY_CHUNKS;
  104. _DBGKD_GET_VERSION64 = packed record
  105. MajorVersion: Word;
  106. MinorVersion: Word;
  107. ProtocolVersion: Word;
  108. Flags: Word;
  109. MachineType: Word;
  110. MaxPacketType: Byte;
  111. MaxStateChange: Byte;
  112. MaxManipulate: Byte;
  113. Simulation: Byte;
  114. Unused: Word;
  115. KernBase: Int64;
  116. PsLoadedModuleList: Int64;
  117. DebuggerDataList: Int64;
  118. end;
  119. DBGKD_GET_VERSION64 = _DBGKD_GET_VERSION64;
  120. PDBGKD_GET_VERSION64 = ^_DBGKD_GET_VERSION64;
  121. TCnSystemDebugControl = class(TComponent)
  122. private
  123. FKernelBase: Int64;
  124. procedure KbcWait4IBE;
  125. {* 等待键盘缓冲区为空}
  126. procedure InternalCopyMemory(Code: DEBUG_CONTROL_CODE; Address: Cardinal;
  127. Memory: Pointer; Length: Cardinal);
  128. {* 封装的内存复制操作}
  129. procedure SysGetVersion;
  130. {* 封装获取版本号的操作}
  131. function GetKernelBase: Cardinal;
  132. public
  133. constructor Create(AOwner: TComponent); override;
  134. destructor Destroy; override;
  135. function InPortB(Port: DWORD): Byte;
  136. {* 读物理端口}
  137. procedure OutPortB(Port: DWORD; Value: Byte);
  138. {* 写物理端口}
  139. // 以下是读写物理端口的具体应用封装
  140. procedure SimuKeyDown(VKey: Cardinal);
  141. {* 模拟按下一个键}
  142. procedure SimuKeyUp(VKey: Cardinal);
  143. {* 模拟抬起一个键}
  144. procedure SimuKey(VKey: Cardinal);
  145. {* 模拟按下抬起一个键}
  146. procedure BeepOn(Freq: Integer);
  147. {* 以指定频率开始让扬声器发声}
  148. procedure BeepOff;
  149. {* 让扬声器停止发声}
  150. function ReadCMOS(Index: Byte): Byte;
  151. {* 读 CMOS 内容}
  152. function ReadFirstHardDiskSerialNumber: string;
  153. {* 读取硬盘序列号}
  154. procedure ReadKernelMemory(Address: Cardinal; Memory: Pointer;
  155. Length: Cardinal);
  156. {* 读取内核空间指定地址的指定长度的内容,内容将复制到 Memory 指的空间中}
  157. procedure WriteKernelMemory(Address: Cardinal; Memory: Pointer;
  158. Length: Cardinal);
  159. {* 将指定 Memory 地址的指定长度的内容写入内核空间指定地址}
  160. procedure ReadPhysicalMemory(Address: Cardinal; Memory: Pointer;
  161. Length: Cardinal);
  162. {* 读取物理指定地址的指定长度的内容,内容将复制到 Memory 指的空间中}
  163. procedure WritePhysicalMemory(Address: Cardinal; Memory: Pointer;
  164. Length: Cardinal);
  165. {* 将指定 Memory 地址的指定长度的内容写入指定物理地址}
  166. property KernelBase: Cardinal read GetKernelBase;
  167. {* 内核映像基址,有 MZ 俩字符}
  168. end;
  169. implementation
  170. const
  171. KBC_KEY_CMD = $64; // 键盘数据端口号
  172. KBC_KEY_DATA = $60; // 键盘操作端口号
  173. type
  174. TZwSystemDebugControl = function (
  175. ControlCode: _DEBUG_CONTROL_CODE;
  176. InputBuffer: Pointer;
  177. InputBufferLength: ULONG;
  178. OutputBuffer: Pointer;
  179. OutputBufferLength: ULONG;
  180. ReturnLength: PULONG): LongInt; stdcall;
  181. var
  182. NtDllHandle: THandle = 0;
  183. ZwSystemDebugControl: TZwSystemDebugControl = nil;
  184. { TCnSystemDebugControl }
  185. procedure TCnSystemDebugControl.BeepOff;
  186. var
  187. B: Byte;
  188. begin
  189. B := InPortB($61) and $FC;
  190. OutPortB($61, B);
  191. end;
  192. procedure TCnSystemDebugControl.BeepOn(Freq: Integer);
  193. var
  194. B: Byte;
  195. begin
  196. if (Freq >= 20) and (Freq <= 20000) then
  197. begin
  198. Freq := Trunc(1193181 / Freq);
  199. B := InPortB($61);
  200. if (B and 3) = 0 then
  201. begin
  202. OutPortB($61, (B or 3));
  203. OutPortB($43, $B6);
  204. end;
  205. OutPortB($42, Byte(Freq and $FF));
  206. OutPortB($42, Byte(Freq shr 8));
  207. end;
  208. end;
  209. constructor TCnSystemDebugControl.Create(AOwner: TComponent);
  210. begin
  211. inherited;
  212. if NtDllHandle = 0 then
  213. raise Exception.Create('Only Windows XP/2003 or Later can be Supported.');
  214. end;
  215. destructor TCnSystemDebugControl.Destroy;
  216. begin
  217. inherited;
  218. end;
  219. function TCnSystemDebugControl.InPortB(Port: DWORD): Byte;
  220. var
  221. Value: BYTE;
  222. Io: TIOStruct;
  223. begin
  224. Value := 0;
  225. Io.IoAddr := Port;
  226. Io.Reserved1 := 0;
  227. Io.pBuffer := Pointer(@Value);
  228. Io.NumBYTEs := SizeOf(Byte);
  229. Io.Reserved4 := 1;
  230. Io.Reserved5 := 0;
  231. Io.Reserved6 := 1;
  232. Io.Reserved7 := 0;
  233. ZwSystemDebugControl(SysDbgSysReadIoSpace, @Io, SizeOf(Io), nil, 0, nil);
  234. Result := Value;
  235. end;
  236. procedure TCnSystemDebugControl.KbcWait4IBE;
  237. var
  238. RegVal: DWORD;
  239. begin
  240. repeat
  241. RegVal := InPortB(KBC_KEY_CMD);
  242. until (RegVal and $00000002) = 0;
  243. end;
  244. procedure TCnSystemDebugControl.OutPortB(Port: DWORD; Value: Byte);
  245. var
  246. Io: TIOStruct;
  247. begin
  248. Io.IoAddr := Port;
  249. Io.Reserved1 := 0;
  250. Io.pBuffer := Pointer(@Value);
  251. Io.NumBYTEs := SizeOf(Byte);
  252. Io.Reserved4 := 1;
  253. Io.Reserved5 := 0;
  254. Io.Reserved6 := 1;
  255. Io.Reserved7 := 0;
  256. ZwSystemDebugControl(SysDbgSysWriteIoSpace, @Io, sizeof(Io), nil, 0, nil);
  257. end;
  258. procedure TCnSystemDebugControl.ReadKernelMemory(Address: Cardinal;
  259. Memory: Pointer; Length: Cardinal);
  260. begin
  261. InternalCopyMemory(SysDbgCopyMemoryChunks_0, Address, Memory, Length);
  262. end;
  263. procedure TCnSystemDebugControl.ReadPhysicalMemory(Address: Cardinal;
  264. Memory: Pointer; Length: Cardinal);
  265. begin
  266. InternalCopyMemory(SysDbgCopyMemoryChunks_2, Address, Memory, Length);
  267. end;
  268. procedure TCnSystemDebugControl.WriteKernelMemory(Address: Cardinal;
  269. Memory: Pointer; Length: Cardinal);
  270. begin
  271. InternalCopyMemory(SysDbgCopyMemoryChunks_1, Address, Memory, Length);
  272. end;
  273. procedure TCnSystemDebugControl.WritePhysicalMemory(Address: Cardinal;
  274. Memory: Pointer; Length: Cardinal);
  275. begin
  276. InternalCopyMemory(SysDbgCopyMemoryChunks_3, Address, Memory, Length);
  277. end;
  278. procedure TCnSystemDebugControl.SimuKey(VKey: Cardinal);
  279. begin
  280. SimuKeyDown(VKey);
  281. SimuKeyUp(VKey);
  282. end;
  283. procedure TCnSystemDebugControl.SimuKeyDown(VKey: Cardinal);
  284. var
  285. ScanCode: Cardinal;
  286. begin
  287. ScanCode := MapVirtualKey(VKey, 0);
  288. KBCWait4IBE; //发送数据前应该先等待键盘缓冲区为空
  289. OutPortB(KBC_KEY_CMD, $D2); //发送键盘写入命令, 0xD2:写键盘缓冲区,0xD3:写鼠标缓冲区,
  290. KBCWait4IBE;
  291. OutPortB(KBC_KEY_DATA, ScanCode); //写入按键信息,按下键
  292. end;
  293. procedure TCnSystemDebugControl.SimuKeyUp(VKey: Cardinal);
  294. var
  295. ScanCode: Cardinal;
  296. begin
  297. ScanCode := MapVirtualKey(VKey, 0);
  298. KBCWait4IBE; //等待键盘缓冲区为空
  299. OutPortB(KBC_KEY_CMD, $D2); //发送键盘写入命令
  300. KBCWait4IBE;
  301. OutPortB(KBC_KEY_DATA, (ScanCode or $80)); //写入按键信息,释放键
  302. end;
  303. function GetNtNativeAPIs: Boolean;
  304. begin
  305. if (Win32Platform = VER_PLATFORM_WIN32_NT)
  306. and (Win32MajorVersion >= 5) and (Win32MinorVersion >= 1) then
  307. begin
  308. NtDllHandle := GetModuleHandle('NTDLL.DLL');
  309. if NtDllHandle = 0 then
  310. NtDllHandle := LoadLibrary('NTDLL.DLL');
  311. if NtDllHandle <> 0 then
  312. begin
  313. @ZwSystemDebugControl := GetProcAddress(NtDllHandle, 'ZwSystemDebugControl');
  314. end;
  315. end;
  316. Result := NtDllHandle <> 0;
  317. end;
  318. procedure FreeNtNativeAPIs;
  319. begin
  320. if NtDllHandle <> 0 then
  321. begin
  322. FreeLibrary(NtDllHandle);
  323. NtDllHandle := 0;
  324. end;
  325. end;
  326. procedure TCnSystemDebugControl.InternalCopyMemory(
  327. Code: DEBUG_CONTROL_CODE; Address: Cardinal; Memory: Pointer;
  328. Length: Cardinal);
  329. var
  330. M: MEMORY_CHUNKS;
  331. Len: Integer;
  332. begin
  333. if Code in [SysDbgCopyMemoryChunks_0..SysDbgCopyMemoryChunks_3] then
  334. begin
  335. M.Address := Address;
  336. M.Data := Memory;
  337. M.Length := Length;
  338. ZwSystemDebugControl(Code, @M, SizeOf(MEMORY_CHUNKS), nil, 0, @Len);
  339. end;
  340. end;
  341. function TCnSystemDebugControl.GetKernelBase: Cardinal;
  342. begin
  343. if FKernelBase = 0 then
  344. SysGetVersion;
  345. Result := Cardinal(FKernelBase);
  346. end;
  347. procedure TCnSystemDebugControl.SysGetVersion;
  348. var
  349. Block: DBGKD_GET_VERSION64;
  350. begin
  351. ZwSystemDebugControl(SysDbgSysGetVersion, nil, 0, @Block,
  352. SizeOf(DBGKD_GET_VERSION64), nil);
  353. FKernelBase := Block.KernBase;
  354. end;
  355. function TCnSystemDebugControl.ReadCMOS(Index: Byte): Byte;
  356. begin
  357. OutPortB($70, Index); // 写要读的索引值
  358. // Sleep(0);
  359. Result := InPortB($71); // 读值
  360. end;
  361. function TCnSystemDebugControl.ReadFirstHardDiskSerialNumber: string;
  362. var
  363. I: Integer;
  364. function WaitUntilIdle: Byte;
  365. begin
  366. Result := InPortB($1F7);
  367. while Result >= $80 do
  368. Result := InPortB($1F7);
  369. end;
  370. begin
  371. WaitUntilIdle;
  372. OutPortB($1F6, $A0);
  373. if (WaitUntilIdle and $50) <> $50 then
  374. Exit;
  375. OutPortB($1F6, $A0);
  376. OutPortB($1F7, $EC);
  377. if (WaitUntilIdle and $58) <> $58 then
  378. Exit;
  379. SetLength(Result, 512);
  380. for I := 0 to 511 do
  381. Result[I + 1] := Chr(InPortB($1F0));
  382. end;
  383. initialization
  384. GetNtNativeAPIs;
  385. AdjustDebugPrivilege(True);
  386. finalization
  387. AdjustDebugPrivilege(False);
  388. FreeNtNativeAPIs;
  389. end.