C#编写程序的课程学习

开发 后端
这里介绍C#编写程序,这一课是些简单的东西,了解的可以直接越过。考虑到大多数使用c#的人都是做网站的,可能没有机会接触这些,所以我在这里做一下粗略的介绍。
本文向大家介绍C#编写程序,可能好多人还不了解C#编写程序,没有关系,看完本文你肯定有不少收获,希望本文能教会你更多东西。

C#编写程序第一课:C#使用WINDOW API和对内存的操作

这一课是些简单的东西,了解的可以直接越过。考虑到大多数使用c#的人都是做网站的,可能没有机会接触这些,所以我在这里做一下粗略的介绍。

step 1:认识WINAPI   

windows系统里提供了很多的函数,我们如果做外挂的话,就需要用到其中的函数(以下简称API)。(废话:这些API被封装在系统路径下的DLL文件里。事实上,我们不用关心它在哪,我们只要知道怎么用就可以了,)用起来很简单,格式如下:

  1. public partial class Form1 : Form  
  2. {  
  3.     [DllImport("kernel32.dll")]          \  
  4.     public static extern int ReadProcessMemory( |  
  5.         int hProcess,               |  
  6.         int lpBaseAddress,             |  
  7.         int[] lpBuffer,                >代码段1  
  8.         int nSize,                    |  
  9.         int lpNumberOfBytesWritten         |  
  10.     );                      /  
  11.     ...  
  12.     public Form1()  
  13.     {  
  14.         InitializeComponent();  
  15.         ReadProcessMemory(processhandle,...          >代码2  
  16.         ...  
  17.     }  
  18.     ...  

代码段1就是引用api的代码。我们引用的函数,是做外挂时最常用的函数,从它的名字就可以看的出来它的作用---读取进程内存。(废话:从代码里,我们很容易看的出来,这个函数被封装在了kernel32.dll这个文件里。)引用之后,我们就可以在自己的代码中使用这个函数了(如代码2)。

(废话:WINDOWS还提供很多的API,如果你有兴趣了解的话,可以到网上搜WINAPI手册。想深入了解的话,可以看MSDN。)

step 2:读写内存

下面我来说一下,如何使用上一步引用的那个API读取游戏的数据。先来看看参数:

  1. publicstaticexternintReadProcessMemory(  
  2.  
  3. inthProcess  
  4. //进程,如果你是做外挂的话,它代表你要挂的那个游戏。  
  5.  
  6. intlpBaseAddress  
  7. //你要读取的内存地址  
  8.  
  9. int[]lpBuffer  
  10. //从上面那个参数地址里读出来的东西(调用这个函数的就是为了它)不管这个参数是什么类型,它应该是一个数组,否则读不出东西来  
  11.  
  12. intnSize  
  13. //长度,上一个参数,类型是int,那个长度应该用4  
  14.  
  15. intlpNumberOfBytesWritten//用0就行了,想知道它是干嘛的,自己去MSND吧  

关于第一个参数hProcess如何获取,我过会再说。假设它已经搞定了,那么这个函数,我们需要关心的只有lpBaseAddress和lpBuffer,既读的地址,和读出来的值。(废话:对了,这个函数貌似还有个返回值,我们这里用不到它。如果你有兴趣了解,MSDN)读出来的值out int lpBuffer我们在引用API的时候声明为int型了,但是,我们要从内存里读的值不一定总是int。我们可以多次引用这个API,第3个参数分别用不同的类型。

下面,我们结合实际,来写一段读取诛仙人物HP的代码。首先,我们需要知道人物HP的地址,(废话:如何知道这个地址,用CE还是IE,你自己搞定吧。)我是用IE在这里http://www.ghoffice.com/bbs/read.php?tid-35908-fpage-2.html找到的,它这里是这样写的:

人物基址:[[&H12F830]+&H28]=base

生命:[base+&H254]

(注:&H表示16进制,在C#里我们用0x表示)

一对[]表示读一次地址。也就是说123表示值123,而[123]就表示从地址123读出来的值。几对[],就要用几次

  1. ReadProcessMemory,我们来写下代码:  
  2. int[] Base=new int[1];  
  3.     int[] hp=new int[1];  
  4.     ReadProcessMemory(process, 0x12F830, Base;, 4, 0);//相当于Base=[&H12F830]  
  5.     ReadProcessMemory(process, Base+0x28, Base;, 4, 0);//相当于Base=[Base+&H28]  
  6.     //读出了人物基址base  
  7.     ReadProcessMemory(process, Base+0x254, hp;, 4, 0);//相当于hp=[base+&H254]  
  8.     //读出了hp 

怎么样,很简单吧。

我们读HP只用了3行ReadProcessMemory。有的时候,读某个值可能需要很多对[],就要写N行ReadProcessMemory,这样写起来就很麻烦,看起来也很晕。下面我们来写个函数,让读内存的过程看起来和[]表示法差不多。

  1. //为了看起来好看,函数的名字最好短些,所以我们用r,表示read  
  2. public static int r(int add)  
  3. {  
  4.     int[] r=new int[1];  
  5.     try 
  6.     {  
  7.         ReadProcessMemory(process, add, r, 4, 0);  
  8.       return r[0];  
  9.     }  
  10.     catch (Exception ex)  
  11.     {  
  12.         return -1;  
  13.     }  

这个函数很简单,不用我多说了吧。

有了这个函数,上面的读取HP的代码,我们就可以写成这样了: 

  1. int Base;  
  2.  int hp;  
  3.  Base=r(r(0x12F830)+0x28);  
  4.  //读出了人物基址base  
  5.  hp=r(base+&H254);  
  6.  //读出了hp 

看起来清晰多了吧。

下面我来说下读取字符串,首先引用API:

  1. [DllImport("kernel32.dll")]  
  2. public static extern int ReadProcessMemory(  
  3.     int hProcess,   
  4.     int lpBaseAddress,   
  5.     byte[] lpBuffer,   
  6.     int nSize,   
  7.     int lpNumberOfBytesRead  
  8. ); 

然后和上面一样,写一个读字符串的方法。 

  1.        public static string rString(IntPtr process, uint add)  
  2.         {  
  3.             string[] r;  
  4.             string temp;  
  5.           
  6.  
  7. byte[] b = new byte[256];  
  8.             try 
  9.             {  
  10.                 API.ReadProcessMemory(process, (IntPtr)add, b, 256, (IntPtr)0);  
  11.                 //读出的byte[]要按Unicode编码为字符串  
  12.                 temp = System.Text.Encoding.Unicode.GetString(b);  
  13.                 //截取第一段字符串  
  14.                 r = temp.Split(''\0'');  
  15.                 return r[0];  
  16.             }  
  17.             catch (Exception ex)  
  18.             {  
  19.                 return "error";  
  20.             }  
  21.         } 

这个函数和上面那个函数差不多,多的东西注释里已经写了,也很简单,不必我废话了。

下面,我们来读人物的名字。还是刚才那个帖子里得到的,人物名字偏移如下:

人物角色名:[[base+3a4]+0]

代码如下:

  1. string name;  
  2. name=rString(r(basse + 0x3a4)+0x0);//+0x0可以去掉 

读其他类型的数据和读INT的雷同,我就不废话了,大家自己搞定吧。

现在万事俱备,就差这个process了,下面我来说下,如果获得游戏的进程句柄(废话:进程句柄:一个用来表示某进程的整形值。推广到一般,**句柄,就是表示某**的整形值)。分两步,第一步:

  1. System.Diagnostics.Process[] GamesProcess  
  2.                 = System.Diagnostics.Process.GetProcessesByName("elementclient");  

这一步用的是.NET本身的方法,System.Diagnostics.Process是.NET里的进程类,GetProcessesByName静态方法是通过进程的名字获得进程数组。这行语句执行之后,所有游戏进程就放在了GamesProcess里面。如果你想做多开挂的话,可以通过数组GamesProcess的下标,来确定你要挂的游戏。

第二步:

  1. int ProcessID=GamesProcess[0].Id;  
  2. int process = OpenProcess(0x1F0FFF, 0, ProcessID); 

第1行是获得进程ID,就是任务管理器里看到的PID。第2行就是获得进程句柄。OpenProcess也是一个系统API,也是在kernel32.dll里。他的3个参数和返回值都声明为INT就OK了。如何引用请看step 1。大家应该可以看出来怎么用,第3个参数是进程ID,返回的就是进程句柄(废话:1,2参数做何用,想知道的自己看MSDN。懒人直接用示例里的参数就行了。以后此类废话不再多说了)。

看到这里,大家可以试着写一个读取人物资料的小东西试试了。当然,前提是你要知道资料的地址。

写内存:

  1. WriteProcessMemory(process, (IntPtr)add, bytes, (UInt32)bytes.Length, 0);  

写进程内存函数。这个API的各参数和ReadProcessMemory是一一对应的。大家自己声明,用用看吧。喜欢的话,也可以向上面一样自己写个函数,以简化写内存的代码。在下一课,我们要用这个函数来向游戏里写代码。

下一课将是些更有趣的东西。我们要通过外挂让游戏执行一些操作。敬请期待吧,呵呵。

C#编写程序第二课 C#注入

这一课其实也很简单,只不过知道的人不多而已。

step 3:注入

注入没什么复杂的,它是一个很简单的过程。用语言描述就一句话:在别的程序里写入你的代码,并执行。

实现起来也很简单,就几行代码:

  1. byte[] bytes={0xC3};//我们要写入的代码  
  2. int addr = VirtualAllocEx(process, 0, bytes.Length, 0x1000, 0x40);//一,申请空间  
  3. WriteProcessMemory(process, addr, bytes, bytes.Length, 0);//二,把代码写进去  
  4. int hThread = CreateRemoteThread(process, 0, 0, addr, 0, 0, threadId);//三,执行写入的代码  
  5. WaitForSingleObject(hThread, 0xFFFFFFFF);//等待线程结束  
  6. VirtualFreeEx(process, addr, 0, 0x8000); //四,释放申请的空间  
  7. CloseHandle(hThread);//五,关闭线程句饼  

仔细看一下这几行代码,你会发现非常简单,几乎不需要我多说什么。这几个豆耐特里豆不出来的函数,都是API。根据上面的使用方法,引用一下,就可以用了。你能看懂的那几个参数和返回值,就是需要你关心的。不知道的的参数都不用理会,直接用上面的值就行了。还有疑问的话,可以参考WINAPI手册。值得注意的地方是,第四步释放申请,如果你看了API手册,会发现第三个参数是大小,但如果你用bytes.Length的话就错了,一定要用0。

(废话:如果你不知道怎么根据上面的使用方法引用API,我就简单说两句。以第二行为例,我们看到VirtualAllocEx的返回值和5个参数都是int行,那么这样声明就行:

  1. [DllImport("Kernel32.dll")]//没有特殊说明的话,API一般都是从这个DLL引用的  
  2. public static extern int VirtualAllocEx(  
  3.     int p1,  
  4.     int p2,  
  5.     int p3,  
  6.     int p4,  
  7.     int p5  
  8. ); 

大家可以看出来,要申明一个API只要知道各参数和返回值的类型,以及DLL文件名就可以了。喜欢的话,你可以把参数的名字起的有意义些。)

简简单单几行代码就实现了注入,是不是没你想像的复杂?呵呵。

现在的一个问题就是,代码从何而来?

大家可以使用我的工具将你找到的CALL转换为机器码。(废话:这个工具的原理,就是调用MASM编译,所以任何你在MASM里能使用的语法和指令(限函数内),都可以在这里用,当然,语法和MASM里的语法规则是一样的。使用的方法在附件里有详细的说明,我就不在这里浪费篇章了。)

工具转换得到的结果是型如60b8d0305a00ffd08b561c83c40461c3的字符串,大家可以用下面的方法把它转换为byte[]

  1.         public static byte[] getBytes(string HEX)  
  2.         {  
  3.             byte[] bytes = new byte[HEX.Length / 2];  
  4.             for (int i = 0; i <  bytes.Length; i++)  
  5.             {  
  6.                 bytes[i] = Convert.ToByte(Int32.Parse(HEX.Substring(i * 2 , 2),  
  7.  
  8. System.Globalization.NumberStyles.AllowHexSpecifier));  
  9.             }  
  10.             return bytes;  
  11.         } 

OK,C#编写程序的课程就到这里,大家可以着手试着用C#调用一下游戏里的攻击CALL了.(如果你不会找CALL,你可以试着在此论坛里找找)

【编辑推荐】

  1. 解密C#-SQLite是如何移植的
  2. 看看如何透过JavaScript调用C#函数
  3. 浅析C#事件注册和注销
  4. 示例:C#通过AMO对象浏览SQL SERVER 2005 SSAS
  5. C#隐藏窗口的几种方法
责任编辑:book05 来源: hi.baidu
相关推荐

2010-01-18 17:31:54

C++编写程序

2009-08-19 17:11:49

C#程序集

2009-08-20 17:49:53

学习C#程序

2011-07-05 17:54:43

QT Sqlite ARM

2011-06-27 13:57:42

JavaScript

2015-09-08 13:47:24

C#编写自动关机

2009-08-24 15:46:46

C# SmartPho

2023-07-13 17:17:59

VSCode鸿蒙

2020-07-15 14:51:39

代码C+开发

2009-08-24 16:02:10

C# Windows应

2009-08-12 18:04:44

编写C#多线程

2009-08-14 09:43:59

C#复制构造函数

2009-08-06 16:58:40

C#编写ActiveX

2009-08-25 15:38:12

C# Windows服

2009-08-18 17:08:50

C#编写XML文档

2009-08-18 16:31:19

Visual C#编写

2009-08-25 13:26:49

C#编写asp+

2009-08-28 15:05:35

C#编写Calenda

2019-10-10 10:03:09

开源技术 开发

2009-08-13 17:04:09

C#语言C#程序
点赞
收藏

51CTO技术栈公众号