第一部分——限制程序多开方法
这里有一篇文章讲得很详细了,http://wenku.baidu.com/view/ac9d0215a2161479171128af.html
龙之谷使用的是互斥体方法,何为互斥体?自己丰衣足食吧!
第二部分——验证龙之谷限制多开的方法
如何验证?
先打开一个游戏,不管之
我们要解决的是如何顺利打开第二个游戏,用OD慢慢分析就行
这里说明龙之谷运行的程序是DragonNext.exe而不是dnlauncher.exe
打开OD,在命令行输入bp CreateMutexA,给这个API下断
接着用OD打开DragonNext.exe
果然,程序在调用CreateMutexA的时候被断了下来
再跟踪一下看有什么发现没
到这里,相信大多数读者已经知道如何解除双开限制了吧
第三部分——介绍解除“互斥体限制双开”的几种方法
第一种:关闭互斥体对象。运行一个游戏,打开XueTr
查看龙之谷的进程句柄
找到如下图红框中的这个对象,关闭之,就可以打开第二个游戏了
第二种:使游戏跳过互斥体检测
可以使用HOOK API的手段进行跳过,可以HOOKCreateMutexA,同时也可以HOOK GetLastError。
第四部分——编程实现程序多开
今天我要讲的是利用HOOK API技术实现多开,至于关闭互斥体对象的方法,大家自己参考这篇文章的方法试试
http://www.cnblogs.com/Y4ng/archive/2012/09/06/EnumProcessHandle_EnumMutex.html
实现API的HOOK有两种方法,第一种是修改IAT表;另一种是修改API入口函数前的机器码成jmp,使程序跳转到自定义的函数处。
至于两种方式谁优谁劣,萝卜青菜,各有所爱吧,我今天要讲的是第一种方法的实现,这里有第二种方法实现的文章,大家自己琢磨琢磨。http://bbs.csdn.net/topics/310177841
PE结构的模块(exe/dll/...),有一个IAT表,保存着该模块使用到的API函数的地址,在默认的隐式API调用时,会先跳转到该IAT表中查找API的具体的函数地址,在跳转到具体的地址执行该API。
理解了IAT,就知道如何下手了,看代码吧
#include <windows.h>
#include <process.h>
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNTHeaders;
PIMAGE_OPTIONAL_HEADER pOptHeader;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_THUNK_DATA pThunkData;
PIMAGE_IMPORT_BY_NAME pImportByName;
HMODULE hMod;
DWORD WINAPI MyGetLastError();
DWORD * addr = (DWORD *)GetLastError; //原函数的入口地址
DWORD * myaddr = (DWORD *)MyGetLastError; //自定义函数入口地址
void ThreadProc(void *param);//线程函数
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
if(fdwReason==DLL_PROCESS_ATTACH)
_beginthread(ThreadProc,0,NULL);
return TRUE;
}
void ThreadProc(void *param)
{
hMod = GetModuleHandle(NULL); //获取自身实例句柄
pDosHeader = (PIMAGE_DOS_HEADER)hMod;
pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);
pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);
while(pImportDescriptor->FirstThunk)//遍历ITA表
{
char * dllname = (char *)((BYTE *)hMod + pImportDescriptor->Name);
pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);
int num = 1;
while(pThunkData->u1.Function)
{
PDWORD lpAddr = (DWORD *)((BYTE *)hMod + (DWORD)pImportDescriptor->FirstThunk) +(num-1);
//找到要HOOK的API
if((*lpAddr) == (int)addr)
{
//远程注入自己的函数
DWORD dwOLD;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(lpAddr,&mbi,sizeof(mbi));
VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);
WriteProcessMemory(GetCurrentProcess(),
lpAddr, &myaddr, sizeof(DWORD), NULL);
VirtualProtect(lpAddr,sizeof(DWORD),dwOLD,0);
break;
}
num++;
pThunkData++;
}
pImportDescriptor++;
}
}
//自定义函数体
DWORD WINAPI MyGetLastError()
{
//这个地方可以写出对这个API函数的处理代码
//对于互斥体对象限制双开的,例如“龙之谷”,则对返回错误信息进行设置为0,
//0表示没有错误,也就表示CreateMutexA调用成功
return 0;
}
要控制别的进程,只能通过远程线程,把DLL注入要目标进程。至于注入器的代码我就不贴了,一起打包发到下载区吧,里边都有注释。
插图显示不全,看不清楚的,把图片另存为。
点击下载源码
同样的道理,封包截取工具等,也可以使用HOOK API技术去实现。亲爱的读者们,何不为自己打造一款属于自己的软件呢?