C#如何去遍历一个由C++或E语言编写的本地DLL导出函数呢 不过在这里我建议对PE一无所知的人

你或许应先补补这方面的知识,我不知道为什么PE方面的 应用在C#中怎么这么少,我查阅过相关

C#的知识大概只见一个人写过关于PE的应用 还只是从PE信息中判断执行文件是X86还是X64方式

编译,难道C#程序员真的很差 真的只能会点Asp.Net / MVC?想想看雪论坛那些玩inline-asm /

inline-hook的牛牛 真是感到有很大差距 不过不论什么语言 在我看来其实都差不多 重点在于人是否

有心。虽然我不敢保证C#可以嵌入动态汇编(auto-asm)但是我可以保证C#可以做inline-hook虽然会

的人比较少,不过也还好,至少C#程序员不会是一群渣渣。不过我在写下述代码时,可是累得紧 写

结构体部分有些麻烦 而且C#与C++有些不同 当然也可以动态偏移地址搞定不过那个有些麻烦了,你

想推敲地址可不是那么好玩的事情,可能你自己推敲半天结果发现你推敲错了,那种方法用在结构体

层次较少的情况下的确可以提升逼格 反正别人看不懂就好嘛? 呵呵。下面的代码需要在X86的环境下

使用主要在于该代码中使用的PE信息全是32位的结构体而非64位的PE信息结构体 所以需要X86环境

不过不论是X86还是X64方法都是相等的,只是两者的结构体与对称不太一样而已。

PE格式,是微软Win32环境可移植执行文件如(exe / sys / dll / vxd / vdm)等都是标准的文件格式

PE格式衍生于VAX / VMS上的COFF文件格式,Portable是指对于不同的Windows版本和不同的

CPU类型上PE文件的格式是一样的,或许CPU不一指令与二进制编码不一,但是文件中各种东

西的布局是一至的。

PE文件中第一个字节是MS-DOS信息头即IMAGE_DOS_HEADER与IMAGE_NT_HEADER中包

含许多PE装载器用到。

[csharp] view plaincopy
  1. [STAThread]
  2. unsafe static void Main()
  3. {
  4. IntPtr hFileBase = Win32Native._lopen(@"C:/Windows/System32/ATL.dll", Win32Native.OF_SHARE_COMPAT);
  5. IntPtr hFileMapping = Win32Native.CreateFileMapping(hFileBase, Win32Native.NULL, Win32Native.PAGE_READONLY, 0, 0, null);
  6. IntPtr psDos32pe = Win32Native.MapViewOfFile(hFileMapping, Win32Native.FILE_MAP_READ, 0, 0, Win32Native.NULL);  // e_lfanew 248
  7. IMAGE_DOS_HEADER sDos32pe = (IMAGE_DOS_HEADER)Marshal.PtrToStructure(psDos32pe, typeof(IMAGE_DOS_HEADER));
  8. IntPtr psNt32pe = (IntPtr)(sDos32pe.e_lfanew + (long)psDos32pe);
  9. IMAGE_NT_HEADERS sNt32pe = (IMAGE_NT_HEADERS)Marshal.PtrToStructure(psNt32pe, typeof(IMAGE_NT_HEADERS));
  10. // 63 63 72 75 6E 2E 63 6F 6D
  11. IntPtr psExportDirectory = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, sNt32pe.OptionalHeader.ExportTable.VirtualAddress, Win32Native.NULL);
  12. IMAGE_EXPORT_DIRECTORY sExportDirectory = (IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure(psExportDirectory, typeof(IMAGE_EXPORT_DIRECTORY));
  13. IntPtr ppExportOfNames = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, sExportDirectory.AddressOfNames, Win32Native.NULL);
  14. for (uint i = 0, nNoOfExports = sExportDirectory.NumberOfNames; i < nNoOfExports; i++)
  15. {
  16. IntPtr pstrExportOfName = Win32Native.ImageRvaToVa(psNt32pe, psDos32pe, (uint)Marshal.ReadInt32(ppExportOfNames, (int)(i * 4)), Win32Native.NULL);
  17. Console.WriteLine(Marshal.PtrToStringAnsi(pstrExportOfName));
  18. }
  19. Win32Native.UnmapViewOfFile(psDos32pe);
  20. Win32Native.CloseHandle(hFileMapping);
  21. Win32Native._lclose(hFileBase);
  22. Console.ReadKey(false);
  23. }

包含 入口点 Entry Point

文件偏移地址 File Offset

虚拟地址 Virtual Address(VA)

基地址 Image Base

相对虚拟地址 Relative Virual Address(RVA)

公式:RVA (相对虚拟地址) = VA(虚拟地址) - Image Base (基地址)

文件偏移地址和虚拟地址转换

在X86系统中,每个内存页的大小是4KB

文件偏移地址 File Offset = RVA(相对虚拟地址) - ΔK

文件偏移地址 File Offset = VA(虚拟地址) - Image Base (基地址) - ΔK

详细解释内容请参考百度百科,反正你想真正理解还需要自己去研究PE文件

IMAGE_NT_HEADERS在MS-DOS信息头后面它是标准的Win32执行文件信息头,其中包含了

导入的函数表,导出函数表,资源信息表、CLR运行时头,IAT、TLS表、包括调试信息 等等

我们现在要做的就是获取在DLL中导出的函数名,而DLL是属于标准Win32执行文件中的一种

那么我们则必须要获取到IMAGE_NT_HEADERS结构,实际上需要定位NT结构是很简单的,

因为在规定中NT信息头在DOS信息头后面,即IMAGE_DOS_HEADER.e_lfanew +  IMAGE_DOS_HEADER

所以你会看到我在代码中有这样一句话IntPtr psNt32pe = (IntPtr)(sDos32pe.e_lfanew + (long)psDos32pe);

IMAGE_OPTIONAL_HEADER可选映像头是一个可选结构,但是IMAGE_FILE_HEADER结构不满足PE文件

需求定义的属性,因此这些属性在OPTIONAL结构中定义,因此FILE+OPTIONAL两个结构联合起来 才是一

个完整的PE文件结构,在其中包含了很多重要的信息字段 如 AddressOfEntryPoint、DataDirectory、Subsystem

不过提到DataDirectory我想说一下,在C#中不好定义所以在代码中该字段换了另一种方式定义,DataDirectory

默认是有16个IMAGE_DATA_DIRECTORY的尺寸,所以在代码中你可以看到有很多该类型的定义。它们则是表

示DataDirectory中信息IMAGE_DIRECTORY_ENTRY_EXPORT导出表 我们现在只需要获取它的信息,在这里

我们需要用到ImageRvaToVa(相对虚拟地址到虚拟地址)有人是这样理解的, 物理地址到虚拟地址 不过原来我在

理解时这个地方也是小小纠结了一番,不过后来则释然了。ImageRvaToVa(NT_H, DOS_H, RVA, RvaSection);

IMAGE_DATA_DIRECTORY中包含两个字段,一个VirtualAddress(RVA)另一个为Size(尺寸)获取到结构体中的

RVA但是这个地址我们不管怎么转换都没法使用,对的因为提供给我的地址根本没法用 那么我们则需要把RVA

转换为VA利用上面提到函数,只有默默的感谢微软一番 呵呵,当转换后会得到IMAGE_EXPORT_DIRECTORY

在这里我需要提示一下大家,不是每个DataDirectory包含的RVA对应的结构都是EXPORT每个都有自己独立的

解释结构,不要搞混了 不然肯定会飞高的。

我们需要IMAGE_EXPORT_DIRECTORY中NumberOfNames(函数名总数)与AddressOfNames(函数名地址)

两个字段中的内容,不过AddressOfNames中包含的是相对虚拟地址RVA,所以我们需要做一次转换,会返回有

效char**的指针前提你提供的数据有效否则返回NULL,由于C#中你懂的char占两个字节,即char=wchar_t那么

我们查看指针中的数据肯定会有问题DLL导出函数名全部是Ascii编码,所以为了方便在C#专用干脆IntPtr方便通过

Marshal进行转换最后只是进行一个资源释放的操作好了基本就是这个样子剩下的还需要大家自己去理解多说无益

[csharp] view plaincopy
  1. using System;
  2. using System.Runtime.InteropServices;
  3. // #include "stdafx.h"
  4. // #include <ImageHlp.h>
  5. // #include <Windows.h>
  6. // #pragma comment(lib, "ImageHlp.lib")
[csharp] view plaincopy
  1. static partial class Win32Native
  2. {
  3. [DllImport("dbghelp", SetLastError = true)] // PIMAGE_SECTION_HEADER LastRvaSection
  4. public static extern IntPtr ImageRvaToVa(IntPtr NtHeaders, IntPtr Base, uint Rva, int LastRvaSection);
  5. [DllImport("kernel32", SetLastError = true)]
  6. public static extern IntPtr _lopen(string lpPathName, int iReadWrite);
  7. [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  8. public static extern IntPtr CreateFileMapping(IntPtr hFile, int lpFileMappingAttributes, int flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
  9. [DllImport("kernel32.dll", SetLastError = true)]
  10. public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, int dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, int dwNumberOfBytesToMap);
  11. [DllImport("kernel32.dll", SetLastError = true)]
  12. public static extern int UnmapViewOfFile(IntPtr hMapFile);
  13. [DllImport("kernel32.dll", SetLastError = true)]
  14. public static extern int _lclose(IntPtr hFile);
  15. [DllImport("kernel32.dll", SetLastError = true)]
  16. public static extern int CloseHandle(IntPtr hObject);
  17. }
  18. static partial class Win32Native
  19. {
  20. public const int NULL = 0;
  21. public const int OF_SHARE_COMPAT = 0;
  22. public const int PAGE_READONLY = 2;
  23. public const int FILE_MAP_READ = 4;
  24. public const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
  25. }
  26. [StructLayout(LayoutKind.Sequential)]
  27. public struct IMAGE_DOS_HEADER
  28. {
  29. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
  30. public char[] e_magic;       // Magic number
  31. public ushort e_cblp;    // Bytes on last page of file
  32. public ushort e_cp;      // Pages in file
  33. public ushort e_crlc;    // Relocations
  34. public ushort e_cparhdr;     // Size of header in paragraphs
  35. public ushort e_minalloc;    // Minimum extra paragraphs needed
  36. public ushort e_maxalloc;    // Maximum extra paragraphs needed
  37. public ushort e_ss;      // Initial (relative) SS value
  38. public ushort e_sp;      // Initial SP value
  39. public ushort e_csum;    // Checksum
  40. public ushort e_ip;      // Initial IP value
  41. public ushort e_cs;      // Initial (relative) CS value
  42. public ushort e_lfarlc;      // File address of relocation table
  43. public ushort e_ovno;    // Overlay number
  44. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
  45. public ushort[] e_res1;    // Reserved words
  46. public ushort e_oemid;       // OEM identifier (for e_oeminfo)
  47. public ushort e_oeminfo;     // OEM information; e_oemid specific
  48. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
  49. public ushort[] e_res2;    // Reserved words
  50. public int e_lfanew;      // File address of new exe header
  51. private string _e_magic
  52. {
  53. get { return new string(e_magic); }
  54. }
  55. public bool isValid
  56. {
  57. get { return _e_magic == "MZ"; }
  58. }
  59. }
  60. [StructLayout(LayoutKind.Explicit)]
  61. public struct IMAGE_OPTIONAL_HEADERS
  62. {
  63. [FieldOffset(0)]
  64. public MagicType Magic;
  65. [FieldOffset(2)]
  66. public byte MajorLinkerVersion;
  67. [FieldOffset(3)]
  68. public byte MinorLinkerVersion;
  69. [FieldOffset(4)]
  70. public uint SizeOfCode;
  71. [FieldOffset(8)]
  72. public uint SizeOfInitializedData;
  73. [FieldOffset(12)]
  74. public uint SizeOfUninitializedData;
  75. [FieldOffset(16)]
  76. public uint AddressOfEntryPoint;
  77. [FieldOffset(20)]
  78. public uint BaseOfCode;
  79. // PE32 contains this additional field
  80. [FieldOffset(24)]
  81. public uint BaseOfData;
  82. [FieldOffset(28)]
  83. public uint ImageBase;
  84. [FieldOffset(32)]
  85. public uint SectionAlignment;
  86. [FieldOffset(36)]
  87. public uint FileAlignment;
  88. [FieldOffset(40)]
  89. public ushort MajorOperatingSystemVersion;
  90. [FieldOffset(42)]
  91. public ushort MinorOperatingSystemVersion;
  92. [FieldOffset(44)]
  93. public ushort MajorImageVersion;
  94. [FieldOffset(46)]
  95. public ushort MinorImageVersion;
  96. [FieldOffset(48)]
  97. public ushort MajorSubsystemVersion;
  98. [FieldOffset(50)]
  99. public ushort MinorSubsystemVersion;
  100. [FieldOffset(52)]
  101. public uint Win32VersionValue;
  102. [FieldOffset(56)]
  103. public uint SizeOfImage;
  104. [FieldOffset(60)]
  105. public uint SizeOfHeaders;
  106. [FieldOffset(64)]
  107. public uint CheckSum;
  108. [FieldOffset(68)]
  109. public SubSystemType Subsystem;
  110. [FieldOffset(70)]
  111. public DllCharacteristicsType DllCharacteristics;
  112. [FieldOffset(72)]
  113. public uint SizeOfStackReserve;
  114. [FieldOffset(76)]
  115. public uint SizeOfStackCommit;
  116. [FieldOffset(80)]
  117. public uint SizeOfHeapReserve;
  118. [FieldOffset(84)]
  119. public uint SizeOfHeapCommit;
  120. [FieldOffset(88)]
  121. public uint LoaderFlags;
  122. [FieldOffset(92)]
  123. public uint NumberOfRvaAndSizes;
  124. [FieldOffset(96)]
  125. public IMAGE_DATA_DIRECTORY ExportTable;
  126. [FieldOffset(104)]
  127. public IMAGE_DATA_DIRECTORY ImportTable;
  128. [FieldOffset(112)]
  129. public IMAGE_DATA_DIRECTORY ResourceTable;
  130. [FieldOffset(120)]
  131. public IMAGE_DATA_DIRECTORY ExceptionTable;
  132. [FieldOffset(128)]
  133. public IMAGE_DATA_DIRECTORY CertificateTable;
  134. [FieldOffset(136)]
  135. public IMAGE_DATA_DIRECTORY BaseRelocationTable;
  136. [FieldOffset(144)]
  137. public IMAGE_DATA_DIRECTORY Debug;
  138. [FieldOffset(152)]
  139. public IMAGE_DATA_DIRECTORY Architecture;
  140. [FieldOffset(160)]
  141. public IMAGE_DATA_DIRECTORY GlobalPtr;
  142. [FieldOffset(168)]
  143. public IMAGE_DATA_DIRECTORY TLSTable;
  144. [FieldOffset(176)]
  145. public IMAGE_DATA_DIRECTORY LoadConfigTable;
  146. [FieldOffset(184)]
  147. public IMAGE_DATA_DIRECTORY BoundImport;
  148. [FieldOffset(192)]
  149. public IMAGE_DATA_DIRECTORY IAT;
  150. [FieldOffset(200)]
  151. public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
  152. [FieldOffset(208)]
  153. public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
  154. [FieldOffset(216)]
  155. public IMAGE_DATA_DIRECTORY Reserved;
  156. }
  157. [StructLayout(LayoutKind.Sequential)]
  158. public struct IMAGE_FILE_HEADER
  159. {
  160. public ushort Machine;
  161. public ushort NumberOfSections;
  162. public uint TimeDateStamp;
  163. public uint PointerToSymbolTable;
  164. public uint NumberOfSymbols;
  165. public ushort SizeOfOptionalHeader;
  166. public ushort Characteristics;
  167. }
  168. public enum MachineType : ushort
  169. {
  170. Native = 0,
  171. I386 = 0x014c,
  172. Itanium = 0x0200,
  173. x64 = 0x8664
  174. }
  175. public enum MagicType : ushort
  176. {
  177. IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b,
  178. IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
  179. }
  180. public enum SubSystemType : ushort
  181. {
  182. IMAGE_SUBSYSTEM_UNKNOWN = 0,
  183. IMAGE_SUBSYSTEM_NATIVE = 1,
  184. IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
  185. IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
  186. IMAGE_SUBSYSTEM_POSIX_CUI = 7,
  187. IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9,
  188. IMAGE_SUBSYSTEM_EFI_APPLICATION = 10,
  189. IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
  190. IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
  191. IMAGE_SUBSYSTEM_EFI_ROM = 13,
  192. IMAGE_SUBSYSTEM_XBOX = 14
  193. }
  194. public enum DllCharacteristicsType : ushort
  195. {
  196. RES_0 = 0x0001,
  197. RES_1 = 0x0002,
  198. RES_2 = 0x0004,
  199. RES_3 = 0x0008,
  200. IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040,
  201. IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
  202. IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100,
  203. IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
  204. IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
  205. IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
  206. RES_4 = 0x1000,
  207. IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
  208. IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
  209. }
  210. [StructLayout(LayoutKind.Sequential)]
  211. public struct IMAGE_DATA_DIRECTORY
  212. {
  213. public uint VirtualAddress;
  214. public uint Size;
  215. }
  216. [StructLayout(LayoutKind.Sequential)]
  217. public struct IMAGE_EXPORT_DIRECTORY
  218. {
  219. public uint Characteristics;
  220. public uint TimeDateStamp;
  221. public ushort MajorVersion;
  222. public ushort MinorVersion;
  223. public uint Name;
  224. public uint Base;
  225. public uint NumberOfFunctions;
  226. public uint NumberOfNames;
  227. public uint AddressOfFunctions;     // RVA from base of image
  228. public uint AddressOfNames;     // RVA from base of image
  229. public uint AddressOfNameOrdinals;  // RVA from base of image
  230. }
  231. [StructLayout(LayoutKind.Explicit)]
  232. public struct IMAGE_NT_HEADERS
  233. {
  234. [FieldOffset(0)]
  235. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
  236. public char[] Signature;
  237. [FieldOffset(4)]
  238. public IMAGE_FILE_HEADER FileHeader;
  239. [FieldOffset(24)]
  240. public IMAGE_OPTIONAL_HEADERS OptionalHeader;
  241. private string _Signature
  242. {
  243. get { return new string(Signature); }
  244. }
  245. public bool isValid
  246. {
  247. get { return _Signature == "PE\0\0" && (OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR32_MAGIC || OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR64_MAGIC); }
  248. }
  249. }

转载于:https://www.cnblogs.com/gc2013/p/4664395.html

C# 遍历DLL导出函数相关推荐

  1. windows 查看DLL导出函数的方法

    windows 查看DLL导出函数的方法 点我查看原文 在window下查看动态库的导出函数可以用vs自带的Dependenc工具: 对于VC6.0,VC所带的Depends软件,在VC6安装目录下的 ...

  2. VC++  DLL 导出函数

    VC++ DLL  导出函数 经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关 ...

  3. dll 导出函数 下划线_内核中的代码完整性:深入分析ci.dll

    前言 在某些场景中,如果我们希望在允许某个进程进行特定动作前,以一种可靠的方式确认该进程是否可信,那么验证该进程的Authenticode签名是一个不错的方式.用户模式下的DLL wintrust提供 ...

  4. 内核分析PE获取DLL导出函数地址

    环境:VS2012+WIN8 64 类型:C++编写的WDM驱动程序 测试:VM WIN7 用途:主要用于驱动程序中得到WIN32 API地址,也可得到自定义的DLL中的函数导出地址,记录内核文件相关 ...

  5. DLL导出函数名称改编的解决方法

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  6. MFC DLL 导出函数的定义方式

    一直在鼓捣DLL,每天的工作都是调试一个一个的DLL,往DLL里面添加自己的代码,但是对于DLL一直不太了解啊!今天一查资料,才发现自己对于DLL编写的一些基本知识也不了解.要学习,这篇文章先总结DL ...

  7. windows查看dll导出函数名

    1.找到vcvarsall.bat(我路径在D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC),dos窗口中运行这个bat. 2.运行dum ...

  8. 编写DLL所学所思(1)——导出函数

    烛秋  http://www.cnblogs.com/cswuyg/archive/2011/09/30/dll.html 动态链接库的使用有两种方式,一种是显式调用.一种是隐式调用. (1)     ...

  9. 动态链接库DLL创建及导出函数、调用DLL

    1.动态链接库(dll)概述 没接触dll之前觉得它很神秘,就像是一个黑盒子,既不能直接运行,也不能接收消息.它们是一些独立的文件,其中包含能被可执行程序或其他dll调用来完成某项工作的函数,只有在其 ...

最新文章

  1. 强势推荐一位 Python 原创自动化大佬!
  2. 2005年2月9日(星期三) 晚上,熱 - 大年初一,首次創作。
  3. Laravel 中的 Many-To-Many
  4. python输入输出重定向_Python标准输出重定向
  5. LinkExtractor
  6. python入门练习题-python入门练习题2
  7. givemesomecredit数据_你是如何走上数据分析之路的?
  8. 简洁又快速地处理集合——Java8 Stream(下)
  9. 风口更需冷静 智能家居如何跨越鸿沟?
  10. 单片机ADC采样算法----限幅消抖滤波法
  11. Python Django 初试手记
  12. java.lang.IllegalStateException报警
  13. 学生成绩管理系统 需求规格说明书
  14. 微软Rdlc报表设计器下载 RdlcDesigner
  15. STC8I2CGY-302(BH1750光照度强度模块)
  16. PHP开发微信商家转账到零钱接口
  17. linux解压rar文件,linux下解压rar文件
  18. 劳动节程序员应该知道的知识——计算机
  19. 关于smtp发信的收件人to cc和bcc
  20. 祖传代码如何优化性能?

热门文章

  1. xpath mysql_xpath查询是否具有像mysql这样的Limit选项
  2. 如何设置电脑自动锁屏_办公族如何设置自动关闭显示器,让显示屏锁屏,防止偷看你电脑。...
  3. 回归分析什么时候取对数_技术派|SPSS数据分析心得小结及心得分享!必备收藏...
  4. java 应用监控系统_GitHub - jiangbin216/JavaMonitor: 一款适用于Java应用的在线性能监控系统(JM)...
  5. labview曲线上两点画延长线_自由泳,那些防不胜防的错误动作(上)
  6. JVM 和 HotSpot 的区别?
  7. Android技术栈总结
  8. centos升级默认node版本
  9. windows server 2012 usb redirection with remoteFX
  10. 《构建高可用Linux服务器 第3版》—— 2.7 系统维护时应注意的非技术因素