仅供学习交流,误用于非法用途.
转载请标明出处.
相信有很多朋友在搜索斗地主"基址"的时候发现这个"基址"总是会变,这是为什么呢?
因为这个所谓的基址其实上是"GameLogic.dll"模块相对地址,而每次加载"GameLogic.dll"模块的时候,"GameLogic.dll"模块的加载地址都会改变,所以我们找到的这个"基址"会变得不固定,一直变动.
我想到了两个方法来解决这个问题
方法一:
根据上面的理解,我们搜索到的地址会变动是因为"GameLogic.dll"模块的加载地址在变动,所以我们只要取到"GameLogic.dll"模块的加载地址,就可以通过计算取到我们想要的基址(牌的地址,座位号的地址....)
比如说:
我在右上角
我的手牌 0x08dfc408
右上|我出的牌 0x08dfc8f0
左上|我的右边 0x08dfe6d0
下边|我的左边 0x08dfd7e0
"GameLogic.dll"的起始地址是0x08d00000
那我们就可通过计算:
我的手牌 0x08dfc408 - 0x08d00000 = FC408
右上|我出的牌 0x08dfc8f0 - 0x08d00000 = ?
左上|我的右边 0x08dfe6d0 - 0x08d00000 = ?
下边|我的左边 0x08dfd7e0 - 0x08d00000 = ? //我这里不一一计算了
在我们下次取地址的时候就可以根据"GameLogic.dll"模块的加载地址 + FC408,得到"我的手牌"的地址.
以上是推论,地址是编的,不要直接拿来用
想要取得"GameLogic.dll"的起始地址,在c#里只需要两个类就可以完成,"Process"类和"ProcessModule"类,需要引用"System.Diagnostics"命名空间.
Process 是对进程访问.
ProcessModule 是对进程模块访问.
Process[] p = Process.GetProcessesByName("hlddzSDK");//GetProcessesByName是查找所有匹配的进程名称,返回一个Process的数组 foreach (ProcessModule pm in p[0].Modules)//遍历加载模块 { if (pm.ModuleName == "GameLogic.dll")//如果加载的模块名称是"GameLogic.dll" { return pm.BaseAddress;//返回该模块的内存地址 } }
如果是其他语言需要调用api"CreateToolhelp32Snapshot",这里不多说了,请自行百度.
方法二:
这种方法比较繁琐,是我后来想到的,理论上是可以无视版本更新.
在CE里,我们发现记录牌的地址的数据是有规律的,
比如说我手牌有黑桃K,红桃Q,梅花J.那么在地址中的排列是这样的:
01 0d 00 00 00 00 00 00 ?? ?? 00 00 02 0c 00 00 00 00 00 00 ?? ?? 00 00 03 0b 00 00 00 00 00 00 ?? ?? 00 00
不难发现01是黑桃,0d是k,02是红桃,0c是Q,03梅花,0b是J.??我猜测是数组的下标志.每一张牌中间相隔是个数据,根据这样的规律我们就可以遍历进程中所有的数据进行对比,
只要匹配的话我们就可以判断这段数据是记录牌的信息的一段数据.
想要实现这个功能,需要掉用api,
/// <summary> /// 查询地址空间中内存地址的信息 /// </summary> [DllImport("kernel32.dll")] public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength); public struct MEMORY_BASIC_INFORMATION { public int BaseAddress; public int AllocationBase; public int AllocationProtect; public int RegionSize; public int State; public int Protect; public int lType; } public const int MEM_COMMIT = 0x1000; //已物理分配 public const int MEM_PRIVATE = 0x20000; public const int PAGE_READWRITE = 0x04; //可读写内存
/// <summary> /// 从指定内存中读取字节集数据 /// </summary> /// <param name="handle">进程句柄</param> /// <param name="address">内存地址</param> /// <param name="data">数据存储变量</param> /// <param name="size">读出的数据大小</param> /// <param name="read">数据的实际大小</param> [DllImport("Kernel32.dll")] public static extern bool ReadProcessMemory(IntPtr handle, int address, byte[] data, int size,byte[] read);
以上是引用非托管类库,
VirtualQueryEx应该很少有人用到,解释一下程序的内存是由页组成的,每个页的访问权限和等等是不一样的,
VirtualQueryEx就是访问远程进程的页的信息,得到的信息储存在lpBuffer结构体里.ps:用这个函数是可以实现类似于ce的内存搜索工具的.
下面是代码:
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); int qkdz = 0x000000;//区块地址,从0开始读 IntPtr jcjb = Process.GetProcessesByName("hlddzSDK")[0].Handle;//进程句柄 while (qkdz <= 0x7fffffff)//0x7fffffff之前是用户地址,只要读0-0x7fffffff就可以了 { VirtualQueryEx(jcjb, (IntPtr)qkdz, out mbi, Marshal.SizeOf(mbi));//读出本次读取的页的信息 if (mbi.State == MEM_COMMIT && mbi.Protect == PAGE_READWRITE)//如果该页的信息已经分配,并且可读写 { byte[] dcdsj = new byte[mbi.RegionSize];//读出的数据 byte[] sjdcdsj = new byte[mbi.RegionSize];//实际读出的数据 int qbppdxb = -1;//全部匹配的数组下标 ReadProcessMemory(jcjb, qkdz, dcdsj, mbi.RegionSize, sjdcdsj);//把该页面的所有信息读取的 dcdsj 数组里 for (int i = 0; i < dcdsj.Length - 203; i++)//循环判断匹配牌的格式的的数据 { int jy = i; #region 判断 if (dcdsj[jy] > 4) { continue; }//如果这个数值大于4,就说明不是花色的信息,跳出本次循环,进行下一次循环 jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; }//如果这个数值大于15或者小于1,就说明这不是牌的信息,跳出本次循环,进行下一次循环 jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3;//因为中间有两个值不确定,所以不进行匹配,直接跳过去 if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] > 4) { continue; } jy++; if (dcdsj[jy] > 15 || dcdsj[jy] < 1) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy += 3; if (dcdsj[jy] != 0) { continue; } jy++; if (dcdsj[jy] != 0) { continue; } jy++; #endregion //一直匹配17张牌,这个是手牌,如果全部匹配的话会运行到这里 //全部符合匹配条件之后发现还是有不是牌的数据,只有再添加一个筛选.先把每张牌都添加进一个字符串里, //然后判断字符串里是否已经有了这张牌,如果有了,说明这次匹配的数据不对,因为扑克牌的数据是不会出现重复的,出现重复自然就不是了 string s = ""; bool sfyjcz = true;//是否已经存在 for (int i1 = 0; i1 < 204; i1 += 12) { string bcpk = dcdsj[i + i1].ToString() + "-" + dcdsj[i + i1 + 1].ToString();//本次扑克 if (s.IndexOf(bcpk) == -1) { s = s + bcpk + ","; } else { sfyjcz = false; break; } } if (sfyjcz)//如果所有牌都不一样,就把i的值赋值给qbppdxb,否则的话qbppdxb是-1 { qbppdxb = i; } } if (qbppdxb != -1)//如果qbppdxb的值不是-1说明读出了牌的地址 { return mbi.BaseAddress + qbppdxb;//BaseAddress该页的地址,返回牌的地址 } } qkdz += mbi.RegionSize;//RegionSize该页的大小,读下一个页 }
就这样了其他代码我以后可能会写,看完请回复.
737355009,这是我qq,有问题加我